olap4j-1.0.1.500/0000755000175000017500000000000011772422544013111 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/0000755000175000017500000000000011542502232014564 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/jndi.properties0000644000175000017500000000023211421322444017624 0ustar drazzibdrazzibjava.naming.factory.initial=org.osjava.sj.SimpleContextFactory org.osjava.sj.root=simple-jndi/ org.osjava.sj.jndi.shared=true org.osjava.sj.delimiter=/olap4j-1.0.1.500/testsrc/org/0000755000175000017500000000000011421322442015352 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/0000755000175000017500000000000011711470530016547 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/ConnectionTest.java0000644000175000017500000036725311711466636022405 0ustar drazzibdrazzib/* // $Id: ConnectionTest.java 497 2012-01-30 16:14:48Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.driver.xmla.XmlaOlap4jDriver; import org.olap4j.impl.Bug; import org.olap4j.impl.Olap4jUtil; import org.olap4j.mdx.*; import org.olap4j.mdx.parser.*; import org.olap4j.metadata.*; import org.olap4j.test.TestContext; import org.olap4j.test.TestContext.Tester; import org.olap4j.test.TestContext.Tester.Flavor; import org.olap4j.type.*; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.*; import static org.olap4j.test.TestContext.nameList; /** * Unit test for olap4j Driver and Connection classes. * *

The system property "org.olap4j.test.helperClassName" determines the * name of the helper class. By default, uses {@link org.olap4j.XmlaTester}, * use the XMLA driver. * * @author jhyde * @version $Id: ConnectionTest.java 497 2012-01-30 16:14:48Z lucboudreau $ */ public class ConnectionTest extends TestCase { private TestContext testContext = TestContext.instance(); private TestContext.Tester tester = testContext.getTester(); private static final boolean IS_JDK_16 = System.getProperty("java.version").startsWith("1.6."); /** * Simple strategy to prevent connection leaks: each test that needs a * connection assigns it to this field, and {@link #tearDown()} closes it * if it is not already closed. */ private Connection connection; protected void tearDown() throws Exception { // Simple strategy to prevent connection leaks if (connection != null && !connection.isClosed()) { connection.close(); connection = null; } testContext = null; tester = null; } /** * Driver basics. */ public void testDriver() throws ClassNotFoundException, SQLException { Class clazz = Class.forName(tester.getDriverClassName()); assertNotNull(clazz); assertTrue(Driver.class.isAssignableFrom(clazz)); // driver should have automatically registered itself Driver driver = DriverManager.getDriver(tester.getDriverUrlPrefix()); assertNotNull(driver); // deregister driver DriverManager.deregisterDriver(driver); try { Driver driver2 = DriverManager.getDriver(tester.getDriverUrlPrefix()); fail("expected error, got " + driver2); } catch (SQLException e) { assertEquals("No suitable driver", e.getMessage()); } // register explicitly DriverManager.registerDriver(driver); Driver driver3 = DriverManager.getDriver(tester.getDriverUrlPrefix()); assertNotNull(driver3); // test properties int majorVersion = driver.getMajorVersion(); int minorVersion = driver.getMinorVersion(); assertTrue(majorVersion >= 0); assertTrue(minorVersion >= 0); assertTrue(majorVersion > 0 || minorVersion > 0); // check that the getPropertyInfo method returns something sensible. // We can't test individual properties in this non-driver-specific test. DriverPropertyInfo[] driverPropertyInfos = driver.getPropertyInfo( tester.getDriverUrlPrefix(), new Properties()); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: break; default: assertTrue(driverPropertyInfos.length > 0); } } void assertIsValid(Connection connection, int timeout) { if (!IS_JDK_16) { return; } // We would like to evaluate // assertTrue(connection.isValid(0)); // but this code would not compile on JDK 1.5 or lower. So, we invoke // the same code by reflection. try { java.lang.reflect.Method method = Connection.class.getMethod("isValid", int.class); Boolean b = (Boolean) method.invoke(connection, timeout); assertTrue(b); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof AbstractMethodError) { // 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); } 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); } } /** * Checks that the isClosed method of a Statement, ResultSet or * Connection object returns the expected result. Uses reflection because * the isClosed method only exists from JDBC 4.0 (JDK 1.6) * onwrds. * * @param o Connection, Statement or ResultSet object * @param b Expected result */ void assertIsClosed(Object o, boolean b) { if (!IS_JDK_16) { return; } if (tester.getWrapper() == TestContext.Wrapper.DBCP) { // commons-dbcp 1.1 doesn't support isClosed return; } // assertTrue(statment.isClosed()); try { Class clazz; if (o instanceof Statement) { clazz = Statement.class; } else if (o instanceof ResultSet) { clazz = ResultSet.class; } else if (o instanceof Connection) { clazz = Connection.class; } else { throw new AssertionFailedError( "not a statement, resultSet or connection"); } java.lang.reflect.Method method = clazz.getMethod("isClosed"); Boolean closed = (Boolean) method.invoke(o); if (b) { assertTrue(closed); } else { assertFalse(closed); } } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } public void testConnection() throws ClassNotFoundException, SQLException { Class.forName(tester.getDriverClassName()); // connect using properties and no username/password connection = tester.createConnection(); assertNotNull(connection); // check isClosed, isValid assertFalse(connection.isClosed()); // check valid with no time limit assertIsValid(connection, 0); // check valid with one minute time limit; should be enough assertIsValid(connection, 60); connection.close(); assertTrue(connection.isClosed()); // it's ok to close twice switch (tester.getWrapper()) { case DBCP: // DBCP complains if you close a connection twice. Even though the // JDBC spec is clear that it is OK. break; default: connection.close(); break; } switch (tester.getFlavor()) { case MONDRIAN: // connect using username/password connection = tester.createConnectionWithUserPassword(); assertNotNull(connection); connection.close(); assertTrue(connection.isClosed()); // connect with URL only connection = DriverManager.getConnection(tester.getURL()); assertNotNull(connection); connection.close(); break; case XMLA: // in-process XMLA test does not support username/password break; case REMOTE_XMLA: // connect using username/password connection = tester.createConnectionWithUserPassword(); assertNotNull(connection); // connect with URL only connection = DriverManager.getConnection(tester.getURL()); assertNotNull(connection); connection.close(); break; } assertTrue(connection.isClosed()); } public void testConnectionUnwrap() throws SQLException { // commons-dbcp 1.1 doesn't do wrapping very well switch (tester.getWrapper()) { case DBCP: return; } connection = tester.createConnection(); // Trivial unwrap assertTrue(((OlapWrapper) connection).isWrapperFor(Connection.class)); Connection connection2 = ((OlapWrapper) connection).unwrap(Connection.class); assertEquals(connection2, connection); // Silly unwrap assertTrue(((OlapWrapper) connection).isWrapperFor(Object.class)); Object object = ((OlapWrapper) connection).unwrap(Object.class); assertEquals(object, connection); // Invalid unwrap assertFalse(((OlapWrapper) connection).isWrapperFor(Writer.class)); try { Writer writer = ((OlapWrapper) connection).unwrap(Writer.class); fail("expected exception, got writer" + writer); } catch (SQLException e) { assertTrue(e.getMessage().contains("does not implement")); } // Unwrap and get locale OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final Locale locale = olapConnection.getLocale(); assertEquals(locale, Locale.getDefault()); // Set locale to something else. olapConnection.setLocale(Locale.CANADA_FRENCH); assertEquals(olapConnection.getLocale(), Locale.CANADA_FRENCH); // Against mondrian, Sales cube is localized. final OlapDatabaseMetaData metaData = olapConnection.getMetaData(); final String databaseName = metaData.getDatabaseProductName(); final String databaseVersion = metaData.getDatabaseProductVersion(); if (databaseName.equals("Mondrian XML for Analysis Provider") && databaseVersion.compareTo("3.3") > 0) { olapConnection.setLocale(Locale.US); final Cube salesCubeUs = olapConnection.getOlapSchema().getCubes().get("Sales"); assertEquals("Sales", salesCubeUs.getCaption()); // Switch locales. Note that we have to re-read metadata from the // root (getOlapSchema()). olapConnection.setLocale(Locale.GERMANY); final Cube salesCubeGerman = olapConnection.getOlapSchema().getCubes().get("Sales"); assertEquals("Verkaufen", salesCubeGerman.getCaption()); assertEquals("Cube Verkaufen", salesCubeGerman.getDescription()); olapConnection.setLocale(Locale.FRANCE); final Cube salesCubeFrance = olapConnection.getOlapSchema().getCubes().get("Sales"); assertEquals("Ventes", salesCubeFrance.getCaption()); assertEquals("Cube des ventes", salesCubeFrance.getDescription()); // The sales cube queried when the connection had a different // locale has not been updated. According to the olap4j spec, // behavior is undefined (e.g. the US sales cube might be invalid). // In the xmla-olap4j driver, it stays valid but still shows the // caption under the US locale. assertEquals("Sales", salesCubeUs.getCaption()); // Reset locale. olapConnection.setLocale(Locale.US); } // Try to set locale to null, should get error. try { olapConnection.setLocale(null); fail("expected exception"); } catch (IllegalArgumentException e) { // Set if back olapConnection.setLocale(Locale.getDefault()); } // Get, set role, get available role names. final String s = olapConnection.getRoleName(); // ok if s is null olapConnection.setRoleName(null); assertNull(olapConnection.getRoleName()); olapConnection.setRoleName(s); // ok if role names list is null final List roleNames = olapConnection.getAvailableRoleNames(); if (roleNames != null && s != null) { assertTrue( "role name " + s + " should be in available role names " + roleNames, roleNames.contains(s)); } // Unwrap the mondrian connection. switch (tester.getFlavor()) { case MONDRIAN: // mondrian.olap.Connection does not extend java.sql.Connection // but we should be able to unwrap it regardless final Class mondrianConnectionClass; try { mondrianConnectionClass = Class.forName("mondrian.olap.Connection"); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } final Object mondrianConnection = ((OlapWrapper) connection).unwrap( mondrianConnectionClass); assertNotNull(mondrianConnection); assert mondrianConnectionClass.isInstance(mondrianConnection); } } public void testXmlaCatalogParameter() throws Exception { if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA || tester.getFlavor() == Tester.Flavor.REMOTE_XMLA) { // We won't use the tester itself since we want to test // creating a connection with and without a Catalog parameter. Properties info = new Properties(); connection = DriverManager.getConnection( tester.getURL().replaceFirst("\\;Catalog=FoodMart", ""), info); assertEquals("FoodMart", connection.getCatalog()); final NamedList catalogs = ((OlapConnection) connection).getOlapCatalogs(); assertNotNull(catalogs); Statement statement = connection.createStatement(); OlapStatement olapStatement = TestContext.Wrapper.NONE.unwrap(statement, OlapStatement.class); assertSame(connection, olapStatement.getConnection()); CellSet cellSet = olapStatement.executeOlapQuery( "SELECT FROM [Sales]"); assertSame(statement, cellSet.getStatement()); List axesList = cellSet.getAxes(); assertNotNull(axesList); assertEquals(0, axesList.size()); info.setProperty( XmlaOlap4jDriver.Property.CATALOG.name(), "FoodMart"); connection = DriverManager.getConnection( tester.getURL().replaceFirst("\\;Catalog=FoodMart", ""), info); assertEquals("FoodMart", connection.getCatalog()); info.setProperty( XmlaOlap4jDriver.Property.CATALOG.name(), "FoodMartError"); try { connection = DriverManager.getConnection( tester.getURL().replaceFirst("\\;Catalog=FoodMart", ""), info); Statement statement2 = connection.createStatement(); OlapStatement olapStatement2 = TestContext.Wrapper.NONE.unwrap( statement2, OlapStatement.class); olapStatement2.executeOlapQuery( "SELECT FROM [Sales]"); fail(); } catch (OlapException e) { // no op. } } } public void testDatabaseMetaData() throws SQLException { connection = tester.createConnection(); final OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final OlapDatabaseMetaData databaseMetaData = olapConnection.getMetaData(); // as per testDriver Driver driver = DriverManager.getDriver(tester.getDriverUrlPrefix()); assertNotNull(driver); assertEquals( databaseMetaData.getDriverMajorVersion(), driver.getMajorVersion()); assertEquals( databaseMetaData.getDriverMinorVersion(), driver.getMinorVersion()); final String driverName = databaseMetaData.getDriverName(); // typically a string like "Mondrian olap4j driver" assertTrue( driverName != null && driverName.length() > 10); final String driverVersion = databaseMetaData.getDriverVersion(); // typically a string like "0.9" or "3.1.2" assertTrue( driverVersion != null && driverName.length() > 2); } public void testStatement() throws SQLException { connection = tester.createConnection(); Statement statement = connection.createStatement(); // Closing a statement is idempotent. assertIsClosed(statement, false); statement.close(); assertIsClosed(statement, true); statement.close(); assertIsClosed(statement, true); // Unwrap the statement to get the olap statement. Depending on the // driver, this may or may not be the same object. statement = connection.createStatement(); OlapStatement olapStatement = tester.getWrapper().unwrap(statement, OlapStatement.class); assertNotNull(olapStatement); // Execute a simple query. CellSet cellSet = olapStatement.executeOlapQuery( "SELECT FROM [Sales]"); List axesList = cellSet.getAxes(); assertNotNull(axesList); assertEquals(0, axesList.size()); // Executing another query implicitly closes the previous result set. assertIsClosed(statement, false); assertIsClosed(cellSet, false); CellSet cellSet2 = olapStatement.executeOlapQuery( "SELECT FROM [Sales]"); assertIsClosed(statement, false); assertIsClosed(cellSet, true); // Close the statement; this closes the result set. assertIsClosed(cellSet2, false); statement.close(); assertIsClosed(statement, true); assertIsClosed(cellSet2, true); cellSet.close(); assertIsClosed(statement, true); assertIsClosed(cellSet2, true); assertIsClosed(cellSet, true); // Close the connection. 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]\n" + "WHERE ([Time].[1997].[Q1], [Gender].[F])"); 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)); // filter axis final CellSetAxis filterAxis = cellSet.getFilterAxis(); assertEquals(1, filterAxis.getPositionCount()); final List positions = filterAxis.getPositions(); assertEquals(1, positions.size()); final Position pos0 = positions.get(0); assertEquals(0, pos0.getOrdinal()); // The filter contains members explicitly returned. It does not contain // the members of hierarchies not mentioned on any axis (e.g. // [Marital Status]). assertEquals(2, pos0.getMembers().size()); assertEquals("Q1", pos0.getMembers().get(0).getName()); assertEquals("F", pos0.getMembers().get(1).getName()); // If the query has no WHERE clause, the CellSet has a filter axis, but // it has one position and zero members (i.e. equivalent to "WHERE ()".) CellSet cellSetNoSlicer = olapStatement.executeOlapQuery( "SELECT {[Measures].[Unit Sales]} on 0,\n" + "{[Store].Children} on 1\n" + "FROM [Sales]"); assertEquals(2, cellSetNoSlicer.getAxes().size()); final CellSetAxis filterAxisNoSlicer = cellSetNoSlicer.getFilterAxis(); assertNotNull(filterAxisNoSlicer); assertEquals(1, filterAxisNoSlicer.getPositionCount()); final Position position = filterAxisNoSlicer.getPositions().get(0); assertEquals(0, position.getMembers().size()); } /** * Tests a filter with more than one position. * * @throws SQLException on error */ public void testCompoundFilter() throws SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery( "SELECT {[Measures].[Unit Sales]} on 0,\n" + "{[Product].Children} on 1\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q1] * [Gender].Members"); List axesList = cellSet.getAxes(); assertEquals(2, axesList.size()); final CellSetAxis filterAxis = cellSet.getFilterAxis(); assertEquals(3, filterAxis.getPositionCount()); final List filterPositions = filterAxis.getPositions(); assertEquals(3, filterPositions.size()); final Position filterPosition = filterPositions.get(2); assertEquals(2, filterPosition.getMembers().size()); assertEquals("M", filterPosition.getMembers().get(1).getName()); } /** * Tests a filter with zero positions. * * @throws SQLException on error */ public void testEmptyFilter() throws SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery( "SELECT {[Measures].[Unit Sales]} on 0,\n" + "{[Product].Children} on 1\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q1] * [Gender].Parent"); List axesList = cellSet.getAxes(); assertEquals(2, axesList.size()); final CellSetAxis filterAxis = cellSet.getFilterAxis(); assertEquals(0, filterAxis.getPositionCount()); final List filterPositions = filterAxis.getPositions(); assertEquals(0, filterPositions.size()); assertEquals(2, filterAxis.getAxisMetaData().getHierarchies().size()); final Cell cell = cellSet.getCell(Arrays.asList(0, 0)); assertTrue(cell.isNull()); } /** * Tests a query with no filter (no WHERE clause). * * @throws SQLException on error */ public void testMissingFilter() throws SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery( "SELECT {[Measures].[Unit Sales]} on 0,\n" + "{[Product].Children} on 1\n" + "FROM [Sales]\n"); List axesList = cellSet.getAxes(); assertEquals(2, axesList.size()); final CellSetAxis filterAxis = cellSet.getFilterAxis(); assertEquals(1, filterAxis.getPositionCount()); final List filterPositions = filterAxis.getPositions(); assertEquals(1, filterPositions.size()); final Position position = filterPositions.get(0); assertEquals(0, position.getMembers().size()); assertEquals( 0, filterAxis.getAxisMetaData().getHierarchies().size()); assertTrue(filterAxis.getAxisMetaData().getHierarchies().isEmpty()); final Cell cell = cellSet.getCell(Arrays.asList(0, 0)); assertEquals("24,597", cell.getFormattedValue()); } public void testMeasureVersusMemberCasting() throws Exception { 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]\n" + "WHERE ([Time].[1997].[Q1], [Gender].[F])"); 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(); OlapStatement olapStatement = tester.getWrapper().unwrap(statement, OlapStatement.class); // Execute a query with a syntax error. try { CellSet cellSet = olapStatement.executeOlapQuery( "SELECT an error FROM [Sales]"); fail("expected error, got " + cellSet); } catch (OlapException e) { switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: assertTrue( e.getMessage(), e.getMessage().indexOf("XMLA MDX parse failed") >= 0); break; default: assertTrue( TestContext.getStackTrace(e).indexOf( "Failed to parse query") >= 0); break; } } // Error does not cause statement to become closed. assertIsClosed(olapStatement, false); olapStatement.close(); connection.close(); } private enum Method { ClassName, Mode, Type, TypeName, OlapType } public void testPreparedStatement() throws SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); PreparedOlapStatement pstmt = olapConnection.prepareOlapStatement( "SELECT {\n" + " Parameter(\"P1\", [Store], [Store].[USA].[CA]).Parent,\n" + " ParamRef(\"P1\").Children} ON 0\n" + "FROM [Sales]\n" + "WHERE [Gender].[M]"); OlapParameterMetaData parameterMetaData = pstmt.getParameterMetaData(); int paramCount = parameterMetaData.getParameterCount(); // XMLA driver does not support parameters yet. switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: assertEquals(0, paramCount); return; } // Mondrian driver supports parameters. assertEquals(1, paramCount); int[] paramIndexes = {0, 1, 2}; for (int paramIndex : paramIndexes) { for (Method method : Method.values()) { try { switch (method) { case ClassName: String className = parameterMetaData.getParameterClassName(paramIndex); assertEquals("org.olap4j.metadata.Member", className); break; case Mode: int mode = parameterMetaData.getParameterMode(paramIndex); assertEquals(ParameterMetaData.parameterModeIn, mode); break; case Type: int type = parameterMetaData.getParameterType(paramIndex); assertEquals(Types.OTHER, type); break; case TypeName: String typeName = parameterMetaData.getParameterTypeName(paramIndex); assertEquals("MemberType", typeName); break; case OlapType: Type olapType = parameterMetaData.getParameterOlapType(paramIndex); assertEquals( "MemberType", olapType.toString()); break; default: throw Olap4jUtil.unexpected(method); } if (paramIndex != 1) { fail("expected exception"); } } catch (SQLException e) { if (paramIndex == 1) { throw e; } else { // ok - expecting exception } } } } if (tester.getFlavor() == Tester.Flavor.XMLA) // TODO: upgrade mondrian assertEquals("Sales", pstmt.getCube().getName()); // Check metadata exists. (Support for this method is optional.) final CellSetMetaData metaData = pstmt.getMetaData(); assertEquals("Sales", metaData.getCube().getName()); CellSet cellSet = pstmt.executeQuery(); assertEquals(metaData, cellSet.getMetaData()); assertEquals("Sales", metaData.getCube().getName()); String s = TestContext.toString(cellSet); final String expected = "Axis #0:\n" + "{[Gender].[M]}\n" + "Axis #1:\n" + "{[Store].[USA]}\n" + "{[Store].[USA].[CA].[Alameda]}\n" + "{[Store].[USA].[CA].[Beverly Hills]}\n" + "{[Store].[USA].[CA].[Los Angeles]}\n" + "{[Store].[USA].[CA].[San Diego]}\n" + "{[Store].[USA].[CA].[San Francisco]}\n" + "Row #0: 135,215\n" + "Row #0: \n" + "Row #0: 10,562\n" + "Row #0: 13,574\n" + "Row #0: 12,800\n" + "Row #0: 1,053\n"; TestContext.assertEqualsVerbose(expected, s); // Bind parameter and re-execute. final List positions = cellSet.getAxes().get(0).getPositions(); final Member member = positions.get(positions.size() - 1).getMembers().get(0); assertFalse(pstmt.isSet(1)); // parameter is 'set' even if value is null pstmt.setObject(1, null); assertTrue(pstmt.isSet(1)); pstmt.unset(1); assertFalse(pstmt.isSet(1)); pstmt.setObject(1, member); assertTrue(pstmt.isSet(1)); CellSet cellSet2 = pstmt.executeQuery(); assertIsClosed(cellSet, true); assertIsClosed(cellSet2, false); s = TestContext.toString(cellSet2); final String expected2 = "Axis #0:\n" + "{[Gender].[M]}\n" + "Axis #1:\n" + "{[Store].[USA].[CA]}\n" + "{[Store].[USA].[CA].[San Francisco].[Store 14]}\n" + "Row #0: 37,989\n" + "Row #0: 1,053\n"; TestContext.assertEqualsVerbose(expected2, s); // Unset parameter and re-execute. pstmt.unset(1); cellSet = pstmt.executeQuery(); s = TestContext.toString(cellSet); TestContext.assertEqualsVerbose(expected, s); // Re-execute with a new MDX string. CellSet cellSet3 = pstmt.executeOlapQuery( "SELECT FROM [Sales] WHERE [Time.Weekly].[1997].[3]"); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time.Weekly].[1997].[3]}\n" + "9,518", TestContext.toString(cellSet3)); // Number of parameters has changed. OlapParameterMetaData parameterMetaData1 = pstmt.getParameterMetaData(); assertEquals(0, parameterMetaData1.getParameterCount()); // Try to bind non-existent parameter. try { pstmt.setInt(1, 100); fail("expected exception"); } catch (SQLException e) { // ok } // Execute again. CellSet cellSet4 = pstmt.executeQuery(); assertIsClosed(cellSet4, false); assertIsClosed(cellSet3, true); assertEquals(0, cellSet4.getAxes().size()); assertEquals(9518.0, cellSet4.getCell(0).getValue()); // Re-execute with a parse tree. MdxParser mdxParser = olapConnection.getParserFactory().createMdxParser(olapConnection); SelectNode select = mdxParser.parseSelect( "select {[Gender]} on columns from [sales]\n" + "where [Time].[1997].[Q4]"); CellSet cellSet5 = pstmt.executeOlapQuery(select); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q4]}\n" + "Axis #1:\n" + "{[Gender].[All Gender]}\n" + "Row #0: 72,024\n", TestContext.toString(cellSet5)); // Execute. CellSet cellSet6 = pstmt.executeQuery(); assertIsClosed(cellSet6, false); assertIsClosed(cellSet5, true); assertEquals(1, cellSet6.getAxes().size()); assertEquals(72024.0, cellSet6.getCell(0).getDoubleValue()); // Close prepared statement. assertIsClosed(pstmt, false); pstmt.close(); assertIsClosed(pstmt, true); assertIsClosed(cellSet, true); assertIsClosed(cellSet2, true); assertIsClosed(cellSet6, true); // todo: test all of the PreparedOlapStatement.setXxx methods if (false) { pstmt.getCube(); } } public void testCellSetMetaData() throws SQLException { // Metadata of prepared statement connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); checkCellSetMetaData1( olapConnection, "select {[Gender]} on columns from [sales]\n" + "where [Time].[1997].[Q4]"); // now a query with no explicit slicer checkCellSetMetaData1( olapConnection, "select {[Gender]} on columns from [sales]"); } private void checkCellSetMetaData1( OlapConnection olapConnection, String mdx) throws SQLException { PreparedOlapStatement pstmt = olapConnection.prepareOlapStatement(mdx); final CellSetMetaData cellSetMetaData = pstmt.getMetaData(); checkCellSetMetaData(cellSetMetaData, 1, null); // Metadata of its cellset final CellSet cellSet = pstmt.executeQuery(); checkCellSetMetaData(cellSet.getMetaData(), 1, cellSet); // Metadata of regular statement executing string. final OlapStatement stmt = olapConnection.createStatement(); final CellSet cellSet1 = stmt.executeOlapQuery(mdx); checkCellSetMetaData(cellSet1.getMetaData(), 1, cellSet1); // Metadata of regular statement executing parse tree. MdxParser mdxParser = olapConnection.getParserFactory().createMdxParser(olapConnection); SelectNode select = mdxParser.parseSelect(mdx); final OlapStatement stmt2 = olapConnection.createStatement(); CellSet cellSet2 = stmt2.executeOlapQuery(select); checkCellSetMetaData(cellSet2.getMetaData(), 1, cellSet2); } private void checkCellSetMetaData( CellSetMetaData cellSetMetaData, int axesCount, CellSet cellSet) throws OlapException { assertNotNull(cellSetMetaData); assertEquals(axesCount, cellSetMetaData.getAxesMetaData().size()); assertEquals("Sales", cellSetMetaData.getCube().getName()); int k = -1; final Set unseenHierarchies = new HashSet(cellSetMetaData.getCube().getHierarchies()); for (CellSetAxisMetaData axisMetaData : cellSetMetaData.getAxesMetaData()) { ++k; assertEquals( Axis.Factory.forOrdinal(k), axisMetaData.getAxisOrdinal()); assertEquals(k, axisMetaData.getAxisOrdinal().axisOrdinal()); assertTrue(axisMetaData.getHierarchies().size() > 0); unseenHierarchies.removeAll(axisMetaData.getHierarchies()); assertTrue(axisMetaData.getProperties().size() == 0); if (cellSet != null) { final CellSetAxisMetaData cellSetAxisMetaData = cellSet.getAxes().get(k).getAxisMetaData(); assertEquals(cellSetAxisMetaData, axisMetaData); } } CellSetAxisMetaData axisMetaData = cellSetMetaData.getFilterAxisMetaData(); assertNotNull(axisMetaData); assertEquals(Axis.FILTER, axisMetaData.getAxisOrdinal()); assertTrue(axisMetaData.getHierarchies().size() >= 0); if (false) { // The slicer used to contain all hierarchies not seen on other // axes. No longer true. assertEquals( new HashSet(axisMetaData.getHierarchies()), unseenHierarchies); } else { for (Hierarchy hierarchy : axisMetaData.getHierarchies()) { assertTrue(unseenHierarchies.contains(hierarchy)); } } assertTrue(axisMetaData.getProperties().size() == 0); if (cellSet != null) { assertEquals( cellSet.getFilterAxis().getAxisMetaData(), axisMetaData); assertEquals( 1, cellSet.getFilterAxis().getPositionCount()); assertEquals( 1, cellSet.getFilterAxis().getPositions().size()); } } /** * Tests the {@link CellSetAxisMetaData} class, based on an example * in the javadoc of same class. * * @throws Exception on error */ public void testCellSetAxisMetaData() throws Exception { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final String mdx = "SELECT\n" + " {[Measures].Members} ON COLUMNS,\n" + " CrossJoin([Store].Members, [Gender].Children)\n" + " DIMENSION PROPERTIES\n" + " MEMBER_ORDINAL,\n" + " MEMBER_UNIQUE_NAME,\n" + " DISPLAY_INFO ON ROWS\n" + " FROM [Sales]"; // first via prepared statement final PreparedOlapStatement preparedStmt = olapConnection.prepareOlapStatement(mdx); final CellSetMetaData cellSetMetaData = preparedStmt.getMetaData(); checkAxisMetaData(cellSetMetaData.getAxesMetaData().get(1)); // second via directly executed statement OlapStatement olapStatement = olapConnection.createStatement(); final CellSet cellSet = olapStatement.executeOlapQuery(mdx); checkAxisMetaData(cellSet.getAxes().get(1).getAxisMetaData()); // third via metadata of direct statement checkAxisMetaData(cellSet.getMetaData().getAxesMetaData().get(1)); } private void checkAxisMetaData(CellSetAxisMetaData cellSetAxisMetaData) { final List hierarchies = cellSetAxisMetaData.getHierarchies(); assertEquals(2, hierarchies.size()); assertEquals("Store", hierarchies.get(0).getName()); assertEquals("Gender", hierarchies.get(1).getName()); final List properties = cellSetAxisMetaData.getProperties(); switch (tester.getFlavor()) { case MONDRIAN: // todo: fix mondrian driver. If there are 3 properties and 2 // hierarchies, that's 6 properties total assertEquals(3, properties.size()); break; default: assertEquals(6, properties.size()); break; } assertEquals("MEMBER_ORDINAL", properties.get(0).getName()); assertEquals("MEMBER_UNIQUE_NAME", properties.get(1).getName()); assertEquals("DISPLAY_INFO", properties.get(2).getName()); } public void testCellSet() throws SQLException { connection = tester.createConnection(); Statement statement = connection.createStatement(); final OlapStatement olapStatement = tester.getWrapper().unwrap(statement, OlapStatement.class); final CellSet cellSet = olapStatement.executeOlapQuery( "SELECT\n" + " {[Measures].[Unit Sales],\n" + " [Measures].[Store Sales]} ON COLUMNS\n," + " Crossjoin({[Gender].[M]}, [Product].Children) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q2]"); String s = TestContext.toString(cellSet); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q2]}\n" + "Axis #1:\n" + "{[Measures].[Unit Sales]}\n" + "{[Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Gender].[M], [Product].[Drink]}\n" + "{[Gender].[M], [Product].[Food]}\n" + "{[Gender].[M], [Product].[Non-Consumable]}\n" + "Row #0: 3,023\n" + "Row #0: 6,004.80\n" + "Row #1: 22,558\n" + "Row #1: 47,869.17\n" + "Row #2: 6,037\n" + "Row #2: 12,935.16\n", s); } public void testCell() throws Exception { connection = tester.createConnection(); Statement statement = connection.createStatement(); final OlapStatement olapStatement = tester.getWrapper().unwrap(statement, OlapStatement.class); CellSet cellSet = olapStatement.executeOlapQuery( "SELECT\n" + " {[Measures].[Unit Sales],\n" + " [Measures].[Store Sales]} ON COLUMNS\n," + " Crossjoin({[Gender].[M]}, [Product].Children) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q2]"); // cell column#1, row#2 // cellOrdinal = colOrdinal + rowOrdinal * columnCount // = 1 + 2 * 2 // = 5 // access method 1 Cell cell = cellSet.getCell(5); assertEquals(5, cell.getOrdinal()); if (tester.getFlavor() != TestContext.Tester.Flavor.XMLA // FIXME || tester.getFlavor() != TestContext.Tester.Flavor.REMOTE_XMLA) { assertEquals(12935.16, cell.getValue()); } assertEquals(12935.16, cell.getDoubleValue()); assertEquals("12,935.16", cell.getFormattedValue()); assertEquals(cellSet, cell.getCellSet()); // access method 2 cell = cellSet.getCell(Arrays.asList(1, 2)); assertEquals(5, cell.getOrdinal()); // access method 3 cell = cellSet.getCell( cellSet.getAxes().get(0).getPositions().get(1), cellSet.getAxes().get(1).getPositions().get(2)); assertEquals(5, cell.getOrdinal()); assertEquals(Arrays.asList(1, 2), cell.getCoordinateList()); assertEquals( "#,###.00", cell.getPropertyValue(Property.StandardCellProperty.FORMAT_STRING)); assertFalse(cell.isEmpty()); assertFalse(cell.isError()); assertFalse(cell.isNull()); assertNull(cell.getErrorText()); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: // TODO: implement drill-through in XMLA driver break; default: final ResultSet resultSet = cell.drillThrough(); final ResultSetMetaData metaData = resultSet.getMetaData(); // Most databases return 5 columns. Derby returns 9 because of // 4 columns in the ORDER BY clause. assertTrue(metaData.getColumnCount() >= 5); assertEquals("Year", metaData.getColumnLabel(1)); assertEquals("Store Sales", metaData.getColumnLabel(5)); resultSet.close(); break; } // cell out of range using getCell(int) try { Cell cell2 = cellSet.getCell(-5); fail("expected exception, got " + cell2); } catch (IndexOutOfBoundsException e) { // ok } // cell out of range using getCell(int) try { Cell cell2 = cellSet.getCell(105); fail("expected exception, got " + cell2); } catch (IndexOutOfBoundsException e) { // ok } // cell out of range using getCell(List) try { Cell cell2 = cellSet.getCell(Arrays.asList(2, 1)); fail("expected exception, got " + cell2); } catch (IndexOutOfBoundsException e) { // ok } // cell out of range using getCell(Position...) is not possible; but // number of positions might be wrong try { // too few dimensions Cell cell2 = cellSet.getCell(cellSet.getAxes().get(0).getPositions().get(0)); fail("expected exception, got " + cell2); } catch (IllegalArgumentException e) { // ok } try { // too many dimensions Cell cell2 = cellSet.getCell( cellSet.getAxes().get(0).getPositions().get(0), cellSet.getAxes().get(1).getPositions().get(0), cellSet.getAxes().get(0).getPositions().get(0)); fail("expected exception, got " + cell2); } catch (IllegalArgumentException e) { // ok } // We provide positions from the wrong axes, but the provider doesn't // notice that they're wrong. That's OK. cell = cellSet.getCell( cellSet.getAxes().get(1).getPositions().get(1), cellSet.getAxes().get(0).getPositions().get(1)); assertEquals(3, cell.getOrdinal()); // Null cell cellSet = olapStatement.executeOlapQuery( "with member [Measures].[X] as 'IIF([Measures].[Store Sales]>10000,[Measures].[Store Sales],Null)'\n" + "select\n" + "{[Measures].[X]} on columns,\n" + "{[Product].[Product Department].members} on rows\n" + "from Sales"); cell = cellSet.getCell(0); assertFalse(cell.isNull()); cell = cellSet.getCell(2); assertTrue(cell.isNull()); // Empty cell cellSet = olapStatement.executeOlapQuery( "select from [Sales]\n" + "where ([Time].[1997].[Q4].[12],\n" + " [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth].[Portsmouth Imported Beer],\n" + " [Store].[All Stores].[USA].[WA].[Bellingham])"); cell = cellSet.getCell(0); assertTrue(cell.isEmpty()); // Error cell cellSet = olapStatement.executeOlapQuery( "with member [Measures].[Foo] as ' Dimensions(-1).Name '\n" + "select {[Measures].[Foo]} on columns from [Sales]"); cell = cellSet.getCell(0); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: // FIXME: mondrian's XMLA provider doesn't indicate that a cell is // an error break; default: assertTrue(cell.isError()); assertEquals("Index '-1' out of bounds", cell.getErrorText()); break; } // todo: test CellSetAxis methods /* public int getAxisOrdinal() public CellSet getCellSet() public CellSetAxisMetaData getAxisMetaData() public List getPositions() public int getPositionCount() public ListIterator iterate() todo: test OlapResultAxisMetaData methods public org.olap4j.Axis getAxisOrdinal() public List getHierarchies() public List getProperties() */ } /** * Tests different scrolling characteristics. * *

In one mode, you request that you get all of the positions on an axis. * You can call {@link CellSetAxis#getPositions()} and * {@link CellSetAxis#getPositions()}. * *

In another mode, you can iterate over the positions, calling * {@link org.olap4j.CellSetAxis#iterator()}. Note that this method returns * a {@link java.util.ListIterator}, which has * {@link java.util.ListIterator#nextIndex()}. We could maybe extend this * interface further, to allow to jump forwards/backwards by N. * *

This test should check that queries work correctly when you ask * for axes as lists and iterators. If you open the query as a list, * you can get it as an iterator, but if you open it as an iterator, you * cannot get it as a list. (Or maybe you can, but it is expensive.) * *

The existing JDBC method {@link Connection#createStatement(int, int)}, * where the 2nd parameter has values such as * {@link ResultSet#TYPE_FORWARD_ONLY} and * {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, might be the way to invoke * those two modes. * *

Note that cell ordinals are not well-defined until axis lengths are * known. Test that cell ordinal property is not available if the statement * is opened in this mode. * *

It was proposed that there would be an API to get blocks of cell * values. Not in the spec yet. */ public void testScrolling() { // todo: submit a query where you ask for different scrolling // characteristics. maybe the values int x = ResultSet.TYPE_SCROLL_INSENSITIVE; int y = ResultSet.TYPE_FORWARD_ONLY; // are how to ask for these characteristics. also need to document this // behavior in the API and the spec. in one mode, } /** * Tests creation of an MDX parser, and converting an MDX statement into * a parse tree. * *

Also create a set of negative tests. Do we give sensible errors if * the MDX is misformed. * *

Also have a set of validator tests, which check that the functions * used exist, are applied to arguments of the correct type, and members * exist. */ public void testParsing() throws SQLException { // parse connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); MdxParser mdxParser = olapConnection.getParserFactory().createMdxParser(olapConnection); SelectNode select = mdxParser.parseSelect( "with member [Measures].[Foo] as ' [Measures].[Bar] ', FORMAT_STRING='xxx'\n" + " select {[Gender]} on columns, {[Store].Children} on rows\n" + "from [sales]\n" + "where [Time].[1997].[Q4]"); // unparse checkUnparsedMdx(select); // test that get error if axes do not have unique names select = mdxParser.parseSelect( "select {[Gender]} on columns, {[Store].Children} on columns\n" + "from [sales]"); if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA || tester.getFlavor() != Tester.Flavor.XMLA) { // This test requires validator support. return; } MdxValidator validator = olapConnection.getParserFactory().createMdxValidator( olapConnection); try { select = validator.validateSelect(select); fail("expected exception, got " + select); } catch (Exception e) { assertTrue( TestContext.getStackTrace(e) .indexOf("Duplicate axis name 'COLUMNS'.") >= 0); } } private void checkUnparsedMdx(SelectNode select) { checkUnparsedMdx( select, "WITH\n" + "MEMBER [Measures].[Foo] AS\n" + " [Measures].[Bar], FORMAT_STRING = \"xxx\"\n" + "SELECT\n" + "{[Gender]} ON COLUMNS,\n" + "{[Store].Children} ON ROWS\n" + "FROM [sales]\n" + "WHERE [Time].[1997].[Q4]"); } private void checkUnparsedMdx( SelectNode select, String expectedMdx) { StringWriter sw = new StringWriter(); ParseTreeWriter parseTreeWriter = new ParseTreeWriter(sw); select.unparse(parseTreeWriter); String mdx = sw.toString(); TestContext.assertEqualsVerbose( expectedMdx, mdx); } /** * Tests creation of an MDX query from a parse tree. Build the parse tree * programmatically. */ public void testUnparsing() { // Note that the select statement constructed here is equivalent // to the one in testParsing. final IdentifierNode cubeName = new IdentifierNode(new NameSegment("sales")); SelectNode select = new SelectNode( null, new ArrayList(), new ArrayList(), cubeName, new AxisNode( null, false, Axis.FILTER, new ArrayList(), null), new ArrayList()); select.getWithList().add( new WithMemberNode( null, new IdentifierNode( new NameSegment("Measures"), new NameSegment("Foo")), new IdentifierNode( new NameSegment("Measures"), new NameSegment("Bar")), Arrays.asList( new PropertyValueNode( null, "FORMAT_STRING", LiteralNode.createString( null, "xxx"))))); select.getAxisList().add( new AxisNode( null, false, Axis.COLUMNS, new ArrayList(), new CallNode( null, "{}", Syntax.Braces, Arrays.asList( (ParseTreeNode) new IdentifierNode( new NameSegment("Gender")))))); select.getAxisList().add( new AxisNode( null, false, Axis.ROWS, new ArrayList(), new CallNode( null, "{}", Syntax.Braces, new CallNode( null, "Children", Syntax.Property, new IdentifierNode( new NameSegment("Store")))))); select.getFilterAxis().setExpression( new IdentifierNode( new NameSegment("Time"), new NameSegment("1997"), new NameSegment("Q4"))); assertEquals(select.getFrom(), cubeName); checkUnparsedMdx(select); // Now with a subquery in the FROM clause. SelectNode subSelect = new SelectNode( null, new ArrayList(), new ArrayList(), new IdentifierNode(new NameSegment("warehouse")), new AxisNode( null, false, Axis.FILTER, new ArrayList(), null), new ArrayList()); select.setFrom(subSelect); assertEquals(select.getFrom(), subSelect); checkUnparsedMdx( select, "WITH\n" + "MEMBER [Measures].[Foo] AS\n" + " [Measures].[Bar], FORMAT_STRING = \"xxx\"\n" + "SELECT\n" + "{[Gender]} ON COLUMNS,\n" + "{[Store].Children} ON ROWS\n" + "FROM (\n" + " SELECT\n" + " FROM [warehouse])\n" + "WHERE [Time].[1997].[Q4]"); } public void testBuildParseTree() { // It is an error to create a select node with a filter axis whose type // is not filter try { SelectNode select = new SelectNode( null, new ArrayList(), new ArrayList(), new IdentifierNode(new NameSegment("sales")), new AxisNode( null, false, Axis.COLUMNS, new ArrayList(), null), new ArrayList()); fail("expected error, got " + select); } catch (IllegalArgumentException e) { TestContext.checkThrowable(e, "Filter axis must have type FILTER"); } // Create a select node with empty filter axis. It is populated with // a filter axis whose expression is null. SelectNode select = new SelectNode( null, new ArrayList(), new ArrayList(), new IdentifierNode(new NameSegment("sales")), new AxisNode( null, false, Axis.FILTER, new ArrayList(), null), new ArrayList()); final AxisNode filterAxis = select.getFilterAxis(); assertNotNull(filterAxis); assertNull(filterAxis.getExpression()); assertEquals(Axis.FILTER, filterAxis.getAxis()); // Parses to an expression with no WHERE clause checkUnparsedMdx( select, "SELECT\n" + "FROM [sales]"); // Set the filter, see if it takes. select.getFilterAxis().setExpression( new CallNode( null, "()", Syntax.Parentheses, new IdentifierNode( new NameSegment("Measures"), new NameSegment("Store Sales")), new IdentifierNode( new NameSegment("Gender"), new NameSegment("M")))); checkUnparsedMdx( select, "SELECT\n" + "FROM [sales]\n" + "WHERE ([Measures].[Store Sales], [Gender].[M])"); // Set it back to null select.getFilterAxis().setExpression(null); checkUnparsedMdx( select, "SELECT\n" + "FROM [sales]"); } /** * Tests the {@link Cube#lookupMember(java.util.List)} method. */ public void testCubeLookupMember() throws Exception { Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Cube cube = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart") .getCubes() .get("Sales Ragged"); Member member = cube.lookupMember(nameList("Time", "1997", "Q2")); assertEquals("[Time].[1997].[Q2]", member.getUniqueName()); // Member.getChildMemberCount assertEquals(3, member.getChildMemberCount()); // Member.getChildMembers final NamedList childMembers = member.getChildMembers(); assertEquals(3, childMembers.size()); assertEquals( "[Time].[1997].[Q2].[4]", childMembers.get(0).getUniqueName()); assertEquals(0, childMembers.get(0).getChildMemberCount()); assertEquals( "[Time].[1997].[Q2].[6]", childMembers.get("6").getUniqueName()); assertNull(childMembers.get("1")); member = cube.lookupMember(nameList("Time", "1997", "Q5")); assertNull(member); // arguably this should return [Customers].[All Customers]; but it // makes a bit more sense for it to return null member = cube.lookupMember(nameList("Customers")); assertNull(member); member = cube.lookupMember(nameList("Customers", "All Customers")); assertTrue(member.isAll()); } /** * Tests the {@link Cube#lookupMembers(java.util.Set, java.util.List)} * method. */ public void testCubeLookupMembers() throws Exception { Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Cube cube = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart") .getCubes() .get("Sales"); List memberList = cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), nameList("Time", "1997", "Q2")); String expected; switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: // TODO: Fix mondrian's XMLA driver to return members ordered by // level then by ordinal as per XMLA spec expected = "[Time].[1997].[Q2].[4]\n" + "[Time].[1997].[Q2].[5]\n" + "[Time].[1997].[Q2].[6]\n" + "[Time].[1997]\n"; break; default: expected = "[Time].[1997]\n" + "[Time].[1997].[Q2].[4]\n" + "[Time].[1997].[Q2].[5]\n" + "[Time].[1997].[Q2].[6]\n"; } TestContext.assertEqualsVerbose( expected, memberListToString(memberList)); // ask for non-existent member; list should be empty memberList = cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), nameList("Time", "1997", "Q5")); assertTrue(memberList.isEmpty()); // ask for parent & ancestors; should not get duplicates memberList = cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), nameList("Time", "1997", "Q2")); TestContext.assertEqualsVerbose( "[Time].[1997]\n", memberListToString(memberList)); // ask for parent of root member, should not get null member in list memberList = cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), nameList("Product")); assertTrue(memberList.isEmpty()); // ask for siblings and children, and the results should be // hierarchically ordered (as always) memberList = cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.SIBLINGS, Member.TreeOp.CHILDREN), nameList("Time", "1997", "Q2")); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: // TODO: fix mondrian's XMLA driver to return members ordered by // level then ordinal expected = "[Time].[1997].[Q2].[4]\n" + "[Time].[1997].[Q2].[5]\n" + "[Time].[1997].[Q2].[6]\n" + "[Time].[1997].[Q1]\n" + "[Time].[1997].[Q3]\n" + "[Time].[1997].[Q4]\n"; break; default: expected = "[Time].[1997].[Q1]\n" + "[Time].[1997].[Q2].[4]\n" + "[Time].[1997].[Q2].[5]\n" + "[Time].[1997].[Q2].[6]\n" + "[Time].[1997].[Q3]\n" + "[Time].[1997].[Q4]\n"; break; } TestContext.assertEqualsVerbose( expected, memberListToString(memberList)); // siblings of the root member - potentially tricky memberList = cube.lookupMembers( Olap4jUtil.enumSetOf(Member.TreeOp.SIBLINGS), nameList("Time", "1997")); TestContext.assertEqualsVerbose( "[Time].[1998]\n", memberListToString(memberList)); memberList = cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.SIBLINGS, Member.TreeOp.SELF), nameList("Customers", "USA", "OR")); TestContext.assertEqualsVerbose( "[Customers].[USA].[CA]\n" + "[Customers].[USA].[OR]\n" + "[Customers].[USA].[WA]\n", memberListToString(memberList)); } /** * Tests metadata browsing. */ public void testMetadata() throws Exception { Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); OlapDatabaseMetaData metadata = olapConnection.getMetaData(); // We engineered the XMLA test environment to have two catalogs. switch (tester.getFlavor()) { case REMOTE_XMLA: assertEquals(1, olapConnection.getOlapCatalogs().size()); break; case XMLA: assertEquals(2, olapConnection.getOlapCatalogs().size()); break; case MONDRIAN: assertEquals(1, olapConnection.getOlapCatalogs().size()); break; } Cube cube = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart") .getCubes() .get("Sales"); int z = 0; int hierarchyCount = 0; for (Dimension dimension : cube.getDimensions()) { // Call every method of Dimension assertNotNull(dimension.getCaption()); dimension.getDescription(); assertNotNull(dimension.getDefaultHierarchy()); assertEquals( dimension.getName().equals("Time") ? Dimension.Type.TIME : dimension.getName().equals("Measures") ? Dimension.Type.MEASURE : Dimension.Type.OTHER, dimension.getDimensionType()); assertNotNull(dimension.getName()); assertNotNull(dimension.getUniqueName()); for (Hierarchy hierarchy : dimension.getHierarchies()) { ++hierarchyCount; // Call every method of Hierarchy final NamedList rootMemberList = hierarchy.getRootMembers(); if (hierarchy.hasAll()) { assertEquals(1, rootMemberList.size()); } for (Member rootMember : rootMemberList) { assertNull(rootMember.getParentMember()); } assertEquals( rootMemberList, hierarchy.getLevels().get(0).getMembers()); assertNotNull(hierarchy.getDefaultMember()); assertNotNull(hierarchy.getName()); assertNotNull(hierarchy.getUniqueName()); hierarchy.getDescription(); assertNotNull(hierarchy.getCaption()); assertEquals(dimension, hierarchy.getDimension()); for (Level level : hierarchy.getLevels()) { if (level.getCardinality() >= 100) { continue; } if (level.getName().equals("Year")) { assertEquals( Level.Type.TIME_YEARS, level.getLevelType()); assertFalse(level.isCalculated()); ++z; } if (level.getName().equals("Gender")) { assertEquals(Level.Type.REGULAR, level.getLevelType()); assertFalse(level.isCalculated()); ++z; } if (level.getName().equals("Measures")) { assertEquals(Level.Type.REGULAR, level.getLevelType()); assertFalse(level.isCalculated()); ++z; } // 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; // } // } } } } // Make sure every hierarchy which came out through // cube.getDimensions().getHierarchies() also comes out through // cube.getHierarchies(). for (Hierarchy hierarchy : cube.getHierarchies()) { --hierarchyCount; assertNotNull(hierarchy.getName()); } assertEquals(0, hierarchyCount); assertEquals("found Year, Measures, Gender levels", 3, z); // Look for the Time.Weekly hierarchy, the 2nd hierarchy in the Time // dimension. final Hierarchy timeWeeklyHierarchy = cube.getHierarchies().get("Time.Weekly"); assertNotNull(timeWeeklyHierarchy); assertEquals("Time", timeWeeklyHierarchy.getDimension().getName()); assertEquals( 2, timeWeeklyHierarchy.getDimension().getHierarchies().size()); Cube warehouseCube = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart") .getCubes() .get("Warehouse"); int count = 0; for (NamedSet namedSet : warehouseCube.getSets()) { ++count; assertNotNull(namedSet.getName()); assertNotNull(namedSet.getUniqueName()); assertNotNull(namedSet.getCaption()); namedSet.getDescription(); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: // FIXME: implement getExpression in XMLA driver break; default: assertTrue( namedSet.getExpression().getType() instanceof SetType); } } assertTrue(count > 0); // ~ Member Member member = cube.lookupMember( nameList("Product", "Food", "Marshmallows")); assertNull(member); // we don't sell marshmallows! member = cube.lookupMember( nameList("Product", "Food")); assertNotNull(member); Member member2 = cube.lookupMember( nameList("Product", "All Products", "Food")); assertEquals(member, member2); final Member bread = cube.lookupMember( nameList("Product", "Food", "Baked Goods", "Bread")); assertEquals("[Product].[Food]", member.getUniqueName()); assertEquals("Food", member.getName()); assertEquals( "[Product].[Product Family]", member.getLevel().getUniqueName()); assertEquals(Member.Type.REGULAR, member.getMemberType()); assertEquals( "[Product].[Food].[Baked Goods]", bread.getParentMember().getUniqueName()); final List list = bread.getAncestorMembers(); assertEquals(3, list.size()); assertEquals( "[Product].[Food].[Baked Goods]", list.get(0).getUniqueName()); assertEquals("[Product].[Food]", list.get(1).getUniqueName()); assertEquals("[Product].[All Products]", list.get(2).getUniqueName()); assertEquals("Food", member.getCaption()); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: assertEquals("", member.getDescription()); assertEquals(204, member.getOrdinal()); break; default: assertNull(member.getDescription()); // mondrian does not set ordinals correctly assertEquals(-1, member.getOrdinal()); assertEquals(1, member.getDepth()); assertEquals(-1, member.getSolveOrder()); assertFalse(member.isHidden()); assertNull(member.getDataMember()); assertFalse(member.isCalculatedInQuery()); } final NamedList propertyList = member.getProperties(); final Property property = propertyList.get("MEMBER_CAPTION"); assertEquals("Food", member.getPropertyFormattedValue(property)); assertEquals("Food", member.getPropertyValue(property)); assertFalse(member.isAll()); // All member final Member allProductsMember = member.getParentMember(); assertEquals( "[Product].[All Products]", allProductsMember.getUniqueName()); assertEquals("(All)", allProductsMember.getLevel().getName()); assertEquals( "[Product].[(All)]", allProductsMember.getLevel().getUniqueName()); assertEquals(1, allProductsMember.getLevel().getMembers().size()); assertTrue(allProductsMember.isAll()); assertNull(allProductsMember.getParentMember()); // ~ Property assertEquals("MEMBER_CAPTION", property.getName()); assertEquals("MEMBER_CAPTION", property.getUniqueName()); assertEquals( Olap4jUtil.enumSetOf(Property.TypeFlag.MEMBER), property.getType()); assertEquals(Datatype.STRING, property.getDatatype()); // PARENT_LEVEL property final Property parentLevelProperty = propertyList.get("PARENT_LEVEL"); assertNotNull(parentLevelProperty); assertEquals( 0, allProductsMember.getPropertyValue(parentLevelProperty)); assertEquals(0, member.getPropertyValue(parentLevelProperty)); assertEquals(2, bread.getPropertyValue(parentLevelProperty)); // PARENT_UNIQUE_NAME property final Property parentUniqueNameProperty = propertyList.get("PARENT_UNIQUE_NAME"); assertNotNull(parentUniqueNameProperty); assertNull( allProductsMember.getPropertyValue(parentUniqueNameProperty)); assertEquals( "[Product].[All Products]", member.getPropertyValue(parentUniqueNameProperty)); assertEquals( "[Product].[Food].[Baked Goods]", bread.getPropertyValue(parentUniqueNameProperty)); // 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 // sorted by ordinal. 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); // mondrian's olap4j driver returns the invisible member // [Measures].[Profit last Period]; the xmla driver does not, // because XMLA by default does not return invisible measures. if (measure.getName().equals("Profit last Period")) { assertFalse(measure.isVisible()); } else { measureNameSet.add(measure.getName()); } } assertEquals( new HashSet( Arrays.asList( "Unit Sales", "Customer Count", "Profit", "Profit Growth", "Promotion Sales", "Sales Count", "Store Sales", "Store Cost")), measureNameSet); } /** * Test case for {@link org.olap4j.metadata.Schema#getSharedDimensions()}. * Bug 3375355, "getSharedDimensions returns empty result". */ public void testSchemaGetSharedDimensions() throws Exception { Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final List list = new ArrayList(); final NamedList sharedDimensions = olapConnection.getOlapSchema().getSharedDimensions(); for (Dimension dimension : sharedDimensions) { list.add(dimension.getName()); } // note that, per specification, list is sorted assertEquals( Arrays.asList( "Product", "Store", "Store Size in SQFT", "Store Type", "Time", "Warehouse"), list); int hierarchyCount = 0, levelCount = 0; for (Dimension sharedDimension : sharedDimensions) { for (Hierarchy hierarchy : sharedDimension.getHierarchies()) { ++hierarchyCount; for (Level level : hierarchy.getLevels()) { ++levelCount; } } } assertTrue(hierarchyCount > 0); assertTrue(levelCount > 0); } /** * Testcase for bug 3312701, "VirtualCube doesn't show * Calculated Members" */ public void testVirtualCubeCmBug() throws Exception { Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Cube warehouseSalesCube = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart") .getCubes() .get("Warehouse and Sales"); Set measureVcNameSet = new HashSet(); for (Measure measure : warehouseSalesCube.getMeasures()) { measureVcNameSet.add(measure.getName()); } assertEquals( new HashSet( Arrays.asList( "Sales Count", "Store Cost", "Store Sales", "Unit Sales", "Profit", "Profit Growth", "Profit Per Unit Shipped", "Store Invoice", "Supply Time", "Units Ordered", "Units Shipped", "Warehouse Cost", "Warehouse Profit", "Warehouse Sales", "Average Warehouse Sale")), measureVcNameSet); } /** * Testcase for bug 1868075, "Query on ragged hierarchy gives only empty * cells". */ public void testRagged() throws SQLException { connection = tester.createConnection(); Statement statement = connection.createStatement(); final OlapStatement olapStatement = tester.getWrapper().unwrap(statement, OlapStatement.class); final CellSet cellSet = olapStatement.executeOlapQuery( "SELECT\n" + "{[Product].[All Products].[Drink].[Alcoholic Beverages].Children,\n" + "[Product].[All Products].[Food].[Baked Goods].Children} ON COLUMNS,\n" + "CrossJoin([Store].[All Stores].[USA].[CA].Children,\n" + "[Time].[1997].[Q1].Children) ON ROWS\n" + "FROM [Sales Ragged]"); String s = TestContext.toString(cellSet); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]}\n" + "{[Product].[Food].[Baked Goods].[Bread]}\n" + "Axis #2:\n" + "{[Store].[USA].[CA].[Alameda], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[Alameda], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[Alameda], [Time].[1997].[Q1].[3]}\n" + "{[Store].[USA].[CA].[Beverly Hills], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[Beverly Hills], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[Beverly Hills], [Time].[1997].[Q1].[3]}\n" + "{[Store].[USA].[CA].[Los Angeles], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[Los Angeles], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[Los Angeles], [Time].[1997].[Q1].[3]}\n" + "{[Store].[USA].[CA].[San Francisco], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[San Francisco], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[San Francisco], [Time].[1997].[Q1].[3]}\n" + "Row #0: \n" + "Row #0: \n" + "Row #1: \n" + "Row #1: \n" + "Row #2: \n" + "Row #2: \n" + "Row #3: 22\n" + "Row #3: 63\n" + "Row #4: 28\n" + "Row #4: 59\n" + "Row #5: 28\n" + "Row #5: 39\n" + "Row #6: 70\n" + "Row #6: 51\n" + "Row #7: 89\n" + "Row #7: 51\n" + "Row #8: 27\n" + "Row #8: 54\n" + "Row #9: 6\n" + "Row #9: 2\n" + "Row #10: 3\n" + "Row #10: 7\n" + "Row #11: 2\n" + "Row #11: 10\n", s); } /** * Tests members from a parent-child hierarchy. * * @throws ClassNotFoundException * @throws SQLException */ public void testParentChild() throws ClassNotFoundException, SQLException { Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final CellSet cellSet = olapConnection.createStatement().executeOlapQuery( "select {[Measures].[Org Salary]} on 0,\n" + " Head([Employees].Members, 10) DIMENSION PROPERTIES DEPTH ON 1\n" + "from [HR]"); final CellSetAxis rowsAxis = cellSet.getAxes().get(1); assertEquals(10, rowsAxis.getPositionCount()); Member member0 = rowsAxis.getPositions().get(0).getMembers().get(0); assertEquals("All Employees", member0.getName()); assertEquals(0, member0.getDepth()); Member member1 = rowsAxis.getPositions().get(1).getMembers().get(0); assertEquals("[Employees].[Sheri Nowmer]", member1.getUniqueName()); assertEquals(1, member1.getDepth()); assertEquals(1, member1.getLevel().getDepth()); assertEquals( member0.getUniqueName(), member1.getParentMember().getUniqueName()); assertEquals(member0, member1.getParentMember()); Member member2 = rowsAxis.getPositions().get(2).getMembers().get(0); assertTrue( member2.getUniqueName().equals( "[Employees].[Derrick Whelply]") || member2.getUniqueName().equals( "[Employees].[Sheri Nowmer].[Derrick Whelply]")); assertEquals(2, member2.getDepth()); assertEquals(1, member2.getLevel().getDepth()); final Member parent = member2.getParentMember(); assertNotNull(parent); assertEquals("[Employees].[Sheri Nowmer]", parent.getUniqueName()); assertEquals(1, parent.getDepth()); assertEquals(member2.getLevel(), parent.getLevel()); assertEquals(member1, parent); final CellSetAxis filterAxis = cellSet.getFilterAxis(); assertEquals(1, filterAxis.getPositionCount()); final List positions = filterAxis.getPositions(); assertEquals(1, positions.size()); assertEquals(0, positions.get(0).getOrdinal()); // No WHERE clause, therefore slicer is empty (but not null). assertEquals(0, positions.get(0).getMembers().size()); } /** * Tests the type-derivation for * {@link org.olap4j.mdx.SelectNode#getFrom()} and the {@link CubeType} * class. * * @throws Throwable on error */ public void testCubeType() throws Throwable { if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA || tester.getFlavor() == TestContext.Tester.Flavor.REMOTE_XMLA) { // This test requires validator support. return; } Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final MdxParserFactory parserFactory = olapConnection.getParserFactory(); MdxParser mdxParser = parserFactory.createMdxParser(olapConnection); MdxValidator mdxValidator = parserFactory.createMdxValidator(olapConnection); SelectNode select = mdxParser.parseSelect( "select {[Gender]} on columns from [sales]\n" + "where [Time].[1997].[Q4]"); // CubeType // Before validation, we cannot ask for type try { final ParseTreeNode from = select.getFrom(); assertTrue(from instanceof IdentifierNode); Type type = from.getType(); fail("expected error, got " + type); } catch (UnsupportedOperationException e) { // ignore } select = mdxValidator.validateSelect(select); CubeType cubeType = (CubeType) select.getFrom().getType(); assertEquals("Sales", cubeType.getCube().getName()); assertNull(cubeType.getDimension()); assertNull(cubeType.getHierarchy()); assertNull(cubeType.getLevel()); // Different query based on same cube should have equal CubeType select = mdxParser.parseSelect( "select from [sales]"); select = mdxValidator.validateSelect(select); assertEquals(cubeType, select.getFrom().getType()); // Different query based on different cube should have different // CubeType select = mdxParser.parseSelect( "select from [warehouse and sales]"); select = mdxValidator.validateSelect(select); assertNotSame(cubeType, select.getFrom().getType()); } /** * Tests the type-derivation for query axes * ({@link org.olap4j.mdx.SelectNode#getAxisList()} and * {@link org.olap4j.mdx.SelectNode#getFilterAxis()}), and the * {@link org.olap4j.type.SetType}, * {@link org.olap4j.type.TupleType}, * {@link org.olap4j.type.MemberType} type subclasses. * * @throws Throwable on error */ public void testAxisType() throws Throwable { if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA || tester.getFlavor() == TestContext.Tester.Flavor.REMOTE_XMLA) { // This test requires validator support. return; } Class.forName(tester.getDriverClassName()); // connect using properties and no username/password connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final MdxParserFactory parserFactory = olapConnection.getParserFactory(); MdxParser mdxParser = parserFactory.createMdxParser(olapConnection); MdxValidator mdxValidator = parserFactory.createMdxValidator(olapConnection); SelectNode select = mdxParser.parseSelect( "select ([Gender], [Store]) on columns\n," + "{[Customers].[City].Members} on rows\n" + "from [sales]\n" + "where ([Time].[1997].[Q4], [Marital Status].[S])"); select = mdxValidator.validateSelect(select); // a query is not an expression, so does not have a type assertNull(select.getType()); final AxisNode columnsAxis = select.getAxisList().get(0); // an axis is not an expression, so does not have a type assertNull(columnsAxis.getType()); // ~ SetType final SetType setType = (SetType) columnsAxis.getExpression().getType(); assertNull(setType.getDimension()); assertNull(setType.getHierarchy()); assertNull(setType.getLevel()); assertNotNull(setType.toString()); final Type elementType = setType.getElementType(); // ~ TupleType assertTrue(elementType instanceof TupleType); TupleType tupleType = (TupleType) elementType; assertNotNull(tupleType.toString()); assertNull(tupleType.getDimension()); assertNull(tupleType.getHierarchy()); assertNull(tupleType.getLevel()); final Cube cube = ((CubeType) select.getFrom().getType()).getCube(); final Dimension storeDimension = cube.getDimensions().get("Store"); final Dimension genderDimension = cube.getDimensions().get("Gender"); final Dimension measuresDimension = cube.getDimensions().get("Measures"); final Dimension customersDimension = cube.getDimensions().get("Customers"); assertTrue(tupleType.usesDimension(storeDimension, false)); assertTrue(tupleType.usesDimension(genderDimension, false)); assertFalse(tupleType.usesDimension(measuresDimension, false)); // Other axis is a set of members // ~ MemberType final AxisNode rowsAxis = select.getAxisList().get(1); final Type rowsType = rowsAxis.getExpression().getType(); assertTrue(rowsType instanceof SetType); MemberType memberType = (MemberType) ((SetType) rowsType).getElementType(); assertNotNull(memberType.toString()); // MemberType.getMember is null because we know it belongs to the City // level, but no particular member of that level. assertNull("Customers", memberType.getMember()); assertEquals("City", memberType.getLevel().getName()); assertEquals("Customers", memberType.getHierarchy().getName()); assertEquals("Customers", memberType.getDimension().getName()); assertFalse(memberType.usesDimension(storeDimension, false)); assertTrue(memberType.usesDimension(customersDimension, false)); assertTrue(memberType.usesDimension(customersDimension, true)); // Filter final AxisNode filterAxis = select.getFilterAxis(); assertNull(filterAxis.getType()); final Type filterType = filterAxis.getExpression().getType(); assertTrue(filterType instanceof TupleType); assertEquals( "TupleType, MemberType>", filterType.toString()); } public void testParseQueryWithNoFilter() throws Exception { if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA || tester.getFlavor() != Tester.Flavor.REMOTE_XMLA) { // This test requires validator support. return; } Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final MdxParserFactory parserFactory = olapConnection.getParserFactory(); MdxParser mdxParser = parserFactory.createMdxParser(olapConnection); MdxValidator mdxValidator = parserFactory.createMdxValidator(olapConnection); SelectNode select = mdxParser.parseSelect( "select ([Gender], [Store]) on columns\n," + "{[Customers].[City].Members} on rows\n" + "from [sales]"); select = mdxValidator.validateSelect(select); AxisNode filterAxis = select.getFilterAxis(); assertNotNull(filterAxis); assertNull(filterAxis.getExpression()); try { select = mdxParser.parseSelect( "select ([Gender], [Store]) on columns\n," + "{[Customers].[City].Members} on rows\n" + "from [sales]\n" + "where ()"); fail("expected parse error, got " + select); } catch (RuntimeException e) { assertTrue( TestContext.getStackTrace(e).indexOf( "Syntax error at [4:10], token ')'") >= 0); } } public void testValidateError() throws Exception { if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA || tester.getFlavor() != Tester.Flavor.XMLA) { // This test requires validator support. return; } Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final MdxParserFactory parserFactory = olapConnection.getParserFactory(); MdxParser mdxParser = parserFactory.createMdxParser(olapConnection); MdxValidator mdxValidator = parserFactory.createMdxValidator(olapConnection); SelectNode select = mdxParser.parseSelect( "select ([Gender], [Store]) on columns\n," + "crossjoin([Customers].[City].Members, [Gender].members) on rows\n" + "from [sales]"); AxisNode filterAxis = select.getFilterAxis(); assertNotNull(filterAxis); assertNull(filterAxis.getExpression()); try { select = mdxValidator.validateSelect(select); fail("expected parse error, got " + select); } catch (OlapException e) { assertEquals("Validation error", e.getMessage()); final String stackTrace = TestContext.getStackTrace(e); assertTrue( stackTrace, stackTrace.contains( "Hierarchy '[Gender]' appears in more than one " + "independent axis.")); } } // TODO: test for HierarchyType // TODO: test for DimensionType // TODO: test for LevelType /** * Converts a list of members to a string, one per line. */ static String memberListToString(List list) { final StringBuilder buf = new StringBuilder(); for (Member member : list) { buf.append(member.getUniqueName()).append(TestContext.NL); } return buf.toString(); } public void testStatementCancel() throws Throwable { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final OlapStatement olapStatement = olapConnection.createStatement(); final Throwable[] exceptions = {null}; new Thread( new Runnable() { public void run() { try { Thread.sleep(1000); olapStatement.cancel(); } catch (Throwable e) { exceptions[0] = e; } } } ).start(); try { final CellSet cellSet = olapStatement.executeOlapQuery( "SELECT Filter(\n" + " [Product].Members *\n" + " [Customers].Members *\n" + " [Time].[Time].Members,\n" + " 1 = 0) on columns\n" + "from [Sales]"); fail( "expected exception indicating stmt had been canceled," + " got cellSet " + cellSet); } catch (OlapException e) { assertTrue( e.getMessage(), e.getMessage().indexOf("Query canceled") >= 0); } if (exceptions[0] != null) { throw exceptions[0]; } } public void testStatementTimeout() throws Throwable { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final OlapStatement olapStatement = olapConnection.createStatement(); try { olapStatement.setQueryTimeout(-1); fail("expected exception"); } catch (SQLException e) { assertTrue(e.getMessage().indexOf("illegal timeout value ") >= 0); } olapStatement.setQueryTimeout(1); try { final CellSet cellSet = olapStatement.executeOlapQuery( "SELECT Filter(\n" + " [Store].Members * \n" + " [Customers].Members * \n" + " [Time].[Time].Members, 1 = 0) on columns\n" + "from [Sales]"); fail( "expected exception indicating timeout," + " got cellSet " + cellSet); } catch (OlapException e) { assertTrue( e.getMessage(), e.getMessage().indexOf("Query timeout of ") >= 0); } } public void testCellSetBug() throws SQLException { if (!Bug.BugOlap4j3126853Fixed) { return; } connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final OlapStatement olapStatement = olapConnection.createStatement(); // Note: substitute [Sales Ragged] for [Sales] below and the query // takes a very long time against mondrian's XMLA driver, because // mondrian has a performance bug assigning ordinals to ragged // hierarchies, and XMLA requests ask for member ordinals along with // the other attributes of members. CellSet cellSet = olapStatement.executeOlapQuery( "SELECT " + "{[Product].[All Products].[Drink].[Alcoholic Beverages].Children, [Product].[All Products].[Food].[Baked Goods].Children} ON COLUMNS, " + "CrossJoin([Store].[USA].[CA].Children, [Time].[1997].[Q1].Children) ON ROWS " + "FROM [Sales]"); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]}\n" + "{[Product].[Food].[Baked Goods].[Bread]}\n" + "Axis #2:\n" + "{[Store].[USA].[CA].[Alameda], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[Alameda], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[Alameda], [Time].[1997].[Q1].[3]}\n" + "{[Store].[USA].[CA].[Beverly Hills], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[Beverly Hills], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[Beverly Hills], [Time].[1997].[Q1].[3]}\n" + "{[Store].[USA].[CA].[Los Angeles], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[Los Angeles], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[Los Angeles], [Time].[1997].[Q1].[3]}\n" + "{[Store].[USA].[CA].[San Diego], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[San Diego], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[San Diego], [Time].[1997].[Q1].[3]}\n" + "{[Store].[USA].[CA].[San Francisco], [Time].[1997].[Q1].[1]}\n" + "{[Store].[USA].[CA].[San Francisco], [Time].[1997].[Q1].[2]}\n" + "{[Store].[USA].[CA].[San Francisco], [Time].[1997].[Q1].[3]}\n" + "Row #0: \n" + "Row #0: \n" + "Row #1: \n" + "Row #1: \n" + "Row #2: \n" + "Row #2: \n" + "Row #3: 22\n" + "Row #3: 63\n" + "Row #4: 28\n" + "Row #4: 59\n" + "Row #5: 28\n" + "Row #5: 39\n" + "Row #6: 70\n" + "Row #6: 51\n" + "Row #7: 89\n" + "Row #7: 51\n" + "Row #8: 27\n" + "Row #8: 54\n" + "Row #9: 54\n" + "Row #9: 51\n" + "Row #10: 38\n" + "Row #10: 48\n" + "Row #11: 64\n" + "Row #11: 55\n" + "Row #12: 6\n" + "Row #12: 2\n" + "Row #13: 3\n" + "Row #13: 7\n" + "Row #14: 2\n" + "Row #14: 10\n", TestContext.toString(cellSet)); } public void testCellSetWithCalcMember() throws SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); final OlapStatement olapStatement = olapConnection.createStatement(); CellSet cellSet = olapStatement.executeOlapQuery( "WITH MEMBER [Measures].[Average Profit] AS" + "'[Measures].[Profit] / [Measures].[Sales Count]'" + "SELECT {[Measures].[Average Profit]} ON 0,\n" + "{[Product].Children} ON 1\n" + "FROM [Sales]"); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Average Profit]}\n" + "Axis #2:\n" + "{[Product].[Drink]}\n" + "{[Product].[Food]}\n" + "{[Product].[Non-Consumable]}\n" + "Row #0: $3.68\n" + "Row #1: $3.94\n" + "Row #2: $3.93\n", TestContext.toString(cellSet)); } public void testBuildQuery() throws SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); buildQuery(olapConnection, true); buildQuery(olapConnection, false); } private void buildQuery( OlapConnection olapConnection, boolean useCubeObject) throws OlapException { Catalog catalog = olapConnection.getOlapCatalogs() .get("FoodMart"); Schema schema = catalog.getSchemas().get("FoodMart"); Cube cube = schema.getCubes().get("Sales"); SelectNode query = new SelectNode(); ParseTreeNode cubeNode; if (useCubeObject) { cubeNode = IdentifierNode.parseIdentifier(cube.getUniqueName()); } else { cubeNode = new CubeNode(null, cube); } query.setFrom(cubeNode); AxisNode columnAxis = new AxisNode( null, false, Axis.COLUMNS, null, new CallNode( null, "MEMBERS", Syntax.Property, IdentifierNode.parseIdentifier("[Gender]"))); AxisNode rowAxis = new AxisNode( null, false, Axis.ROWS, null, new CallNode( null, "CHILDREN", Syntax.Property, IdentifierNode.parseIdentifier("[Customers].[USA]"))); query.getAxisList().add(columnAxis); query.getAxisList().add(rowAxis); OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery(query); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Gender].[All Gender]}\n" + "{[Gender].[F]}\n" + "{[Gender].[M]}\n" + "Axis #2:\n" + "{[Customers].[USA].[CA]}\n" + "{[Customers].[USA].[OR]}\n" + "{[Customers].[USA].[WA]}\n" + "Row #0: 74,748\n" + "Row #0: 36,759\n" + "Row #0: 37,989\n" + "Row #1: 67,659\n" + "Row #1: 33,036\n" + "Row #1: 34,623\n" + "Row #2: 124,366\n" + "Row #2: 61,763\n" + "Row #2: 62,603\n", TestContext.toString(cellSet)); } public void testBuildQuery2() throws ClassNotFoundException, SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Schema schema = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart"); Cube cube = schema.getCubes().get("Sales"); Measure measure = cube.getMeasures().get(0); assertEquals("Unit Sales", measure.getName()); Dimension dimPromotionMedia = cube.getDimensions().get("Promotion Media"); // // IdentifierNode cubeNode = // new IdentifierNode( // new IdentifierNode.NameSegment(cube.getUniqueName())); CubeNode cubeNode = new CubeNode(null, cube); MemberNode measuresQuantity = new MemberNode(null, measure); HierarchyNode promotionHierarchyNode = new HierarchyNode(null, dimPromotionMedia.getDefaultHierarchy()); CallNode promotionChildren = new CallNode( null, "children", Syntax.Property, promotionHierarchyNode); // List columnDimensionProperties = new ArrayList(); AxisNode columnAxis = new AxisNode( null, false, Axis.COLUMNS, columnDimensionProperties, new CallNode(null, "{}", Syntax.Braces, measuresQuantity)); List rowDimensionProperties = new ArrayList(); AxisNode rowAxis = new AxisNode( null, false, Axis.ROWS, rowDimensionProperties, new CallNode(null, "{}", Syntax.Braces, promotionChildren)); // SelectNode query = new SelectNode(); query.setFrom(cubeNode); query.getAxisList().add(columnAxis); query.getAxisList().add(rowAxis); // OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery(query); final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw); for (Position row : cellSet.getAxes().get(1)) { for (Position column : cellSet.getAxes().get(0)) { pw.print("ROW:"); for (Member member : row.getMembers()) { pw.print("[" + member.getName() + "]"); } pw.print(" COL:"); for (Member member : column.getMembers()) { pw.print("[" + member.getName() + "]"); } Cell cell = cellSet.getCell(column, row); pw.println(" CELL:" + cell.getFormattedValue()); } } pw.flush(); TestContext.assertEqualsVerbose( "ROW:[Bulk Mail] COL:[Unit Sales] CELL:4,320\n" + "ROW:[Cash Register Handout] COL:[Unit Sales] CELL:6,697\n" + "ROW:[Daily Paper] COL:[Unit Sales] CELL:7,738\n" + "ROW:[Daily Paper, Radio] COL:[Unit Sales] CELL:6,891\n" + "ROW:[Daily Paper, Radio, TV] COL:[Unit Sales] CELL:9,513\n" + "ROW:[In-Store Coupon] COL:[Unit Sales] CELL:3,798\n" + "ROW:[No Media] COL:[Unit Sales] CELL:195,448\n" + "ROW:[Product Attachment] COL:[Unit Sales] CELL:7,544\n" + "ROW:[Radio] COL:[Unit Sales] CELL:2,454\n" + "ROW:[Street Handout] COL:[Unit Sales] CELL:5,753\n" + "ROW:[Sunday Paper] COL:[Unit Sales] CELL:4,339\n" + "ROW:[Sunday Paper, Radio] COL:[Unit Sales] CELL:5,945\n" + "ROW:[Sunday Paper, Radio, TV] COL:[Unit Sales] CELL:2,726\n" + "ROW:[TV] COL:[Unit Sales] CELL:3,607\n", sw.toString()); } /** * Verifies the order of dimensions; they must conform to their * ordinal value. * @throws Exception If something turns sour. */ public void testCubeDimensionsOrder() throws Exception { String dimNames = "[Measures];[Store];[Store Size in SQFT];" + "[Store Type];[Time];[Product];[Promotion Media];[Promotions];" + "[Customers];[Education Level];[Gender];[Marital Status];" + "[Yearly Income];"; Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Cube cube = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart") .getCubes() .get("Sales"); StringBuilder sb = new StringBuilder(); for (Dimension dimension : cube.getDimensions()) { sb.append(dimension.getUniqueName()) .append(";"); } TestContext.assertEqualsVerbose( dimNames, sb.toString()); } public void testCubesDrillthrough() throws Exception { Class.forName(tester.getDriverClassName()); connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Cube cube = olapConnection .getOlapCatalogs() .get("FoodMart") .getSchemas() .get("FoodMart") .getCubes() .get("Sales"); switch (tester.getFlavor()) { case MONDRIAN: assertTrue(cube.isDrillThroughEnabled()); break; case REMOTE_XMLA : case XMLA: assertFalse(cube.isDrillThroughEnabled()); break; default: fail(); break; } } /** * Query with dimension properties. * *

Test case for * * bug 2951656, "Olap4j should not throw IllegalArgumentException". * * @throws java.sql.SQLException on error */ public void _testDimensionProperties() throws SQLException { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); String mdx = "select {[Product].[Product Family].Members} ON COLUMNS,\n" + "{[Store].[Store Name].Members}\n" + " DIMENSION PROPERTIES [Store].[Store Name].[Store Sqft] ON ROWS\n" + "from [Sales]\n" + "where [Measures].[Unit Sales]"; PreparedOlapStatement pstmt = olapConnection.prepareOlapStatement(mdx); pstmt.executeQuery(); } /** *

This test relates to * sourceforge.net/projects/olap4j/forums/forum/577988/topic/3803726 * *

Drivers should return a transaction isolation of * {@link Connection#TRANSACTION_NONE} */ public void testTransactionIsolation() throws SQLException { connection = tester.createConnection(); assertEquals( Connection.TRANSACTION_NONE, connection.getTransactionIsolation()); } public void testSchemaAccessControl() throws Exception { if (tester.getFlavor() == Flavor.XMLA || tester.getFlavor() == Flavor.REMOTE_XMLA) { /* * TODO Implement a way to pass an XmlaRequestCallback to * the tested servlet so we can pass the roles down. */ return; } connection = tester.createConnection(); final OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); try { olapConnection.setRoleName("California manager"); final List list = new ArrayList(); for (Schema schema : olapConnection.getOlapSchemas()) { list.add(schema.getName()); } assertListsEquals( Arrays.asList( "FoodMart"), list); } finally { olapConnection.setRoleName(null); } } public void testCubeAccessControl() throws Exception { if (tester.getFlavor() == Flavor.XMLA || tester.getFlavor() == Flavor.REMOTE_XMLA) { /* * TODO Implement a way to pass an XmlaRequestCallback to * the tested servlet so we can pass the roles down. */ return; } connection = tester.createConnection(); final OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); try { olapConnection.setRoleName("California manager"); final List list = new ArrayList(); for (Cube cube : olapConnection.getOlapSchema().getCubes()) { list.add(cube.getName()); } assertListsEquals( Arrays.asList( "Sales"), list); olapConnection.setRoleName("No HR Cube"); list.clear(); for (Cube cube : olapConnection.getOlapSchema().getCubes()) { list.add(cube.getName()); } assertListsEquals( Arrays.asList( "Sales Ragged", "Warehouse", "Warehouse and Sales", "Sales 2", "Store", "Sales"), list); } finally { olapConnection.setRoleName(null); } } public void testDimensionAccessControl() throws Exception { if (tester.getFlavor() == Flavor.XMLA || tester.getFlavor() == Flavor.REMOTE_XMLA) { /* * TODO Implement a way to pass an XmlaRequestCallback to * the tested servlet so we can pass the roles down. */ return; } connection = tester.createConnection(); final OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); try { olapConnection.setRoleName("California manager"); final List list = new ArrayList(); for (Dimension dimension : olapConnection.getOlapSchema() .getCubes().get("Sales").getDimensions()) { list.add(dimension.getName()); } assertListsEquals( Arrays.asList( "Measures", "Store", "Store Size in SQFT", "Store Type", "Time", "Product", "Promotion Media", "Promotions", "Customers", "Education Level", "Marital Status", "Yearly Income"), list); } finally { olapConnection.setRoleName(null); } } public void testLevelAccessControl() throws Exception { if (tester.getFlavor() == Flavor.XMLA || tester.getFlavor() == Flavor.REMOTE_XMLA) { /* * TODO Implement a way to pass an XmlaRequestCallback to * the tested servlet so we can pass the roles down. */ return; } connection = tester.createConnection(); final OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); try { olapConnection.setRoleName("California manager"); final List list = new ArrayList(); for (Level level : olapConnection.getOlapSchema() .getCubes().get("Sales") .getDimensions().get("Customers") .getHierarchies().get(0) .getLevels()) { list.add(level.getName()); } assertListsEquals( Arrays.asList( "State Province", "City"), list); } finally { olapConnection.setRoleName(null); } } public void testLevelMembersAccessControl() throws Exception { if (tester.getFlavor() == Flavor.XMLA || tester.getFlavor() == Flavor.REMOTE_XMLA) { /* * TODO Implement a way to pass an XmlaRequestCallback to * the tested servlet so we can pass the roles down. */ return; } connection = tester.createConnection(); final OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); try { olapConnection.setRoleName("California manager"); final List list = new ArrayList(); for (Member member : olapConnection.getOlapSchema() .getCubes().get("Sales") .getDimensions().get("Store") .getHierarchies().get(0) .getLevels().get(0) .getMembers()) { list.add(member.getName()); } assertEquals( Arrays.asList( "USA"), list); list.clear(); for (Member member : olapConnection.getOlapSchema() .getCubes().get("Sales") .getDimensions().get("Store") .getHierarchies().get(0) .getLevels().get(1) .getMembers()) { list.add(member.getName()); } assertListsEquals( Arrays.asList( "CA"), list); list.clear(); for (Member member : olapConnection.getOlapSchema() .getCubes().get("Sales") .getDimensions().get("Store") .getHierarchies().get(0) .getLevels().get(2) .getMembers()) { list.add(member.getName()); } assertListsEquals( Arrays.asList( "Alameda", "Beverly Hills", "San Diego", "San Francisco"), list); } finally { olapConnection.setRoleName(null); } } public void testParentChildAccessControl() throws Exception { if (tester.getFlavor() == Flavor.XMLA || tester.getFlavor() == Flavor.REMOTE_XMLA) { /* * TODO Implement a way to pass an XmlaRequestCallback to * the tested servlet so we can pass the roles down. */ return; } connection = tester.createConnection(); final OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); try { olapConnection.setRoleName("California manager"); final Member city = olapConnection.getOlapSchema() .getCubes().get("Sales") .getDimensions().get("Customers") .getHierarchies().get(0) .getLevels().get("City") .getMembers().get(0); assertEquals( 0, city.getChildMembers().size()); final Member state = olapConnection.getOlapSchema() .getCubes().get("Sales") .getDimensions().get("Customers") .getHierarchies().get(0) .getLevels().get("State Province") .getMembers().get(0); assertNull(state.getParentMember()); } finally { olapConnection.setRoleName(null); } } protected void assertListsEquals(List list1, List list2) { Collections.sort(list1); Collections.sort(list2); assertEquals(list1, list2); } } // End ConnectionTest.java olap4j-1.0.1.500/testsrc/org/olap4j/XmlaTester.java0000644000175000017500000001351011707524526021514 0ustar drazzibdrazzib/* // $Id: XmlaTester.java 493 2012-01-24 18:51:30Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.driver.xmla.XmlaOlap4jDriver; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import org.olap4j.test.TestContext; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.*; /** * Implementation of {@link org.olap4j.test.TestContext.Tester} which speaks * to the olap4j driver for XML/A. * * @author jhyde * @version $Id: XmlaTester.java 493 2012-01-24 18:51:30Z lucboudreau $ */ public class XmlaTester implements TestContext.Tester { private final TestContext testContext; final XmlaOlap4jProxy proxy; static final String cookie = XmlaOlap4jDriver.nextCookie(); private Connection connection; /** * Creates an XmlaTester. * *

The {@link org.olap4j.test.TestContext.Tester} API requires a public * constructor with a {@link org.olap4j.test.TestContext} parameter. * * @param testContext Test context * * @throws ClassNotFoundException on error * @throws IllegalAccessException on error * @throws InstantiationException on error * @throws NoSuchMethodException on error * @throws InvocationTargetException on error */ public XmlaTester(TestContext testContext) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { this.testContext = testContext; final Properties properties = testContext.getProperties(); final String catalogUrl = properties.getProperty( TestContext.Property.XMLA_CATALOG_URL.path, "http://foo"); // Include the same catalog URL twice with different catalog names. This // allows us to detect whether operations are restricting to the current // catalog. (Some should, most should not.) Map catalogNameUrls = new HashMap(); catalogNameUrls.put("FoodMart", catalogUrl); catalogNameUrls.put("FoodMart2", catalogUrl); String urlString = properties.getProperty( TestContext.Property.CONNECT_URL.path, "jdbc:mondrian:"); final Class clazz = Class.forName(getProxyClassName()); final Constructor constructor = clazz.getConstructor(Map.class, String.class); this.proxy = (XmlaOlap4jProxy) constructor.newInstance( catalogNameUrls, urlString); XmlaOlap4jDriver.PROXY_MAP.put(cookie, proxy); } public TestContext getTestContext() { return testContext; } public Connection createConnection() throws SQLException { if (connection != null) { connection.close(); connection = null; } try { Class.forName(DRIVER_CLASS_NAME); } catch (ClassNotFoundException e) { throw new RuntimeException("oops", e); } Properties info = new Properties(); info.setProperty( XmlaOlap4jDriver.Property.CATALOG.name(), "FoodMart"); connection = DriverManager.getConnection( getURL(), info); return connection; } public Connection createConnectionWithUserPassword() throws SQLException { final Properties props = new Properties(); return createConnectionWithUserPassword(props); } public Connection createConnectionWithUserPassword( Properties props) throws SQLException { try { Class.forName(DRIVER_CLASS_NAME); } catch (ClassNotFoundException e) { throw new RuntimeException("oops", e); } props.setProperty( XmlaOlap4jDriver.Property.CATALOG.name(), "FoodMart"); if (USER != null) { props.put("user", USER); } if (PASSWORD != null) { props.put("password", PASSWORD); } return DriverManager.getConnection(getURL(), props); } public String getDriverUrlPrefix() { return DRIVER_URL_PREFIX; } public String getDriverClassName() { return DRIVER_CLASS_NAME; } public String getURL() { return "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie; } public Flavor getFlavor() { return Flavor.XMLA; } public TestContext.Wrapper getWrapper() { return TestContext.Wrapper.NONE; } public static void setProxyClassName(String clazz) { PROXY_CLASS_NAME = clazz; } public static String getProxyClassName() { return PROXY_CLASS_NAME; } public static final String DRIVER_CLASS_NAME = "org.olap4j.driver.xmla.XmlaOlap4jDriver"; public static final String DRIVER_URL_PREFIX = "jdbc:xmla:"; private static final String USER = "user"; private static final String PASSWORD = "password"; private static String PROXY_CLASS_NAME = "mondrian.olap4j.MondrianInprocProxy"; } // End XmlaTester.java olap4j-1.0.1.500/testsrc/org/olap4j/CellSetFormatterTest.java0000644000175000017500000006565011711470530023505 0ustar drazzibdrazzib/* // $Id: CellSetFormatterTest.java 498 2012-01-30 16:30:42Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.layout.RectangularCellSetFormatter; import org.olap4j.layout.TraditionalCellSetFormatter; import org.olap4j.test.TestContext; import junit.framework.TestCase; import java.io.PrintWriter; import java.io.StringWriter; import java.sql.Connection; import java.sql.SQLException; /** * Unit test for converting MDX CellSets to text. * * @see org.olap4j.layout.CellSetFormatter * @see org.olap4j.layout.RectangularCellSetFormatter * @see org.olap4j.layout.TraditionalCellSetFormatter * * @author jhyde * @version $Id: CellSetFormatterTest.java 498 2012-01-30 16:30:42Z lucboudreau $ */ public class CellSetFormatterTest extends TestCase { private TestContext testContext = TestContext.instance(); private TestContext.Tester tester = testContext.getTester(); @Override protected void tearDown() throws Exception { testContext = null; tester = null; super.tearDown(); } private static final String query1 = "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]}) on 0,\n" + " {[USA].[CA].[Los Angeles],\n" + " [USA].[WA].[Seattle],\n" + " [USA].[CA].[San Francisco]} on 1\n" + "FROM [Sales]"; /** * Asserts that a query is formatted to an expected piece of text. * * @param queryString MDX query * @param format Desired format * @param expected Expected formatted text * @throws SQLException On error */ private void assertFormat( String queryString, Format format, String expected) throws SQLException { Connection connection = null; try { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap( connection, OlapConnection.class); CellSet result = olapConnection.prepareOlapStatement(queryString).executeQuery(); String resultString = toString(result, format); TestContext.assertEqualsVerbose( expected, resultString); } finally { if (connection != null) { try { connection.close(); } catch (SQLException e) { // ignore } } } } /** * Converts a {@link CellSet} to text. * * @param cellSet Query result * @param format Format * @return Result as text */ static String toString(CellSet cellSet, Format format) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); switch (format) { case TRADITIONAL: new TraditionalCellSetFormatter().format(cellSet, pw); break; case COMPACT_RECTANGULAR: case RECTANGULAR: new RectangularCellSetFormatter( format == Format.COMPACT_RECTANGULAR) .format(cellSet, pw); break; } pw.flush(); return sw.toString(); } public enum Format { /** * Traditional format, one row per cell. */ TRADITIONAL, /** * Rectangular format that is similar to {@link #RECTANGULAR} but omits * vertical bars and is therefore more compact. */ COMPACT_RECTANGULAR, /** * Rectangular format that uses vertical bars and hyphens to draw a * grid. */ RECTANGULAR } // ~ Tests follow ========================================================== public void testQuery1Traditional() throws SQLException { assertFormat( query1, Format.TRADITIONAL, "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Time].[1997].[Q1], [Measures].[Unit Sales]}\n" + "{[Time].[1997].[Q1], [Measures].[Store Sales]}\n" + "{[Time].[1997].[Q2].[4], [Measures].[Unit Sales]}\n" + "{[Time].[1997].[Q2].[4], [Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Store].[USA].[CA].[Los Angeles]}\n" + "{[Store].[USA].[WA].[Seattle]}\n" + "{[Store].[USA].[CA].[San Francisco]}\n" + "Row #0: 6,373\n" + "Row #0: 13,736.97\n" + "Row #0: 1,865\n" + "Row #0: 3,917.49\n" + "Row #1: 6,098\n" + "Row #1: 12,760.64\n" + "Row #1: 2,121\n" + "Row #1: 4,444.06\n" + "Row #2: 439\n" + "Row #2: 936.51\n" + "Row #2: 149\n" + "Row #2: 327.33\n"); } public void testQuery1Compact() throws SQLException { assertFormat( query1, Format.COMPACT_RECTANGULAR, " 1997 \n" + " Q1 Q2 \n" + " 4 \n" + " Unit Sales Store Sales Unit Sales Store Sales\n" + "=== == ============= ========== =========== ========== ===========\n" + "USA CA Los Angeles 6,373 13,736.97 1,865 3,917.49\n" + " WA Seattle 6,098 12,760.64 2,121 4,444.06\n" + " CA San Francisco 439 936.51 149 327.33\n"); } public void testQuery1Rectangular() throws SQLException { assertFormat( query1, Format.RECTANGULAR, "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "| | Unit Sales | Store Sales | Unit Sales | Store Sales |\n" + "+-----+----+---------------+------------+-------------+------------+-------------+\n" + "| USA | CA | Los Angeles | 6,373 | 13,736.97 | 1,865 | 3,917.49 |\n" + "| | WA | Seattle | 6,098 | 12,760.64 | 2,121 | 4,444.06 |\n" + "| | CA | San Francisco | 439 | 936.51 | 149 | 327.33 |\n"); } public void testQueryAllRectangular() throws SQLException { // Similar query with an 'all' member on rows. Need an extra column. assertFormat( "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]}) on 0,\n" + " {[Store],\n" + " [Store].[USA],\n" + " [Store].[USA].[CA],\n" + " [Store].[USA].[CA].[Los Angeles],\n" + " [Store].[USA].[WA]} on 1\n" + "FROM [Sales]", Format.COMPACT_RECTANGULAR, " 1997 \n" + " Q1 Q2 \n" + " 4 \n" + " Unit Sales Store Sales Unit Sales Store Sales\n" + "========== === == =========== ========== =========== ========== ===========\n" + "All Stores 66,291 139,628.35 20,179 42,878.25\n" + " USA 66,291 139,628.35 20,179 42,878.25\n" + " CA 16,890 36,175.20 6,382 13,605.89\n" + " Los Angeles 6,373 13,736.97 1,865 3,917.49\n" + " WA 30,114 63,282.86 9,896 20,926.37\n"); } public void testNonParentRepeatsRectangular() throws SQLException { // "Food.Dairy" follows "Drink.Dairy" but there should still be a '|' // because they are different members with the same caption. assertFormat( "select\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]} on 1,\n" + " {[Product],\n" + " [Product].[Drink].[Dairy],\n" + " [Product].[Food].[Dairy],\n" + " [Product].[Food]} on 0\n" + "FROM [Sales]", Format.RECTANGULAR, "| | All Products |\n" + "| | | Drink | Food |\n" + "| | | Dairy | Dairy | |\n" + "+-------------+--------------+--------------+--------------+--------------+\n" + "| Unit Sales | 266,773 | 4,186 | 12,885 | 191,940 |\n" + "| Store Sales | 565,238.13 | 7,058.60 | 30,508.85 | 409,035.59 |\n"); assertFormat( "select\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]} on 1,\n" + " {[Product],\n" + " [Product].[Drink].[Dairy],\n" + " [Product].[Food].[Dairy],\n" + " [Product].[Food]} on 0\n" + "FROM [Sales]", Format.COMPACT_RECTANGULAR, " All Products \n" + " Drink Food \n" + " Dairy Dairy \n" + "=========== ============ ============ ============ ============\n" + "Unit Sales 266,773 4,186 12,885 191,940\n" + "Store Sales 565,238.13 7,058.60 30,508.85 409,035.59\n"); // Passes the test: Dairy is repeated. // However, the empty last column, signifying [Food] with no child, // is not ideal. What would be better? assertFormat( "select\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]} on 0,\n" + " {[Product],\n" + " [Product].[Drink].[Dairy],\n" + " [Product].[Food].[Dairy],\n" + " [Product].[Food]} on 1\n" + "FROM [Sales]", Format.COMPACT_RECTANGULAR, " Unit Sales Store Sales\n" + "============ ===== ===== ========== ===========\n" + "All Products 266,773 565,238.13\n" + " Drink Dairy 4,186 7,058.60\n" + " Food Dairy 12,885 30,508.85\n" + " 191,940 409,035.59\n"); } public void testEmptyRowsRectangular() throws SQLException { assertFormat( "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]}) on 0,\n" + " {[Store].Parent} on 1\n" + "FROM [Sales]", Format.COMPACT_RECTANGULAR, "1997 \n" + "Q1 Q2 \n" + " 4 \n" + "Unit Sales Store Sales Unit Sales Store Sales\n" + "========== =========== ========== ===========\n"); } public void testEmptyColumnsRectangular() throws SQLException { final String queryString = "select\n" + " crossjoin(\n" + " {[Product].Parent},\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]}) on 0,\n" + " {[Store],\n" + " [Store].[USA],\n" + " [Store].[USA].[CA],\n" + " [Store].[USA].[CA].[Los Angeles],\n" + " [Store].[USA].[WA]} on 1\n" + "FROM [Sales]"; assertFormat( queryString, Format.COMPACT_RECTANGULAR, "All Stores \n" + " USA \n" + " CA \n" + " Los Angeles\n" + " WA \n"); assertFormat( queryString, Format.RECTANGULAR, "| All Stores | | | |\n" + "| | USA | | |\n" + "| | | CA | |\n" + "| | | | Los Angeles |\n" + "| | | WA | |\n"); } public void testFilter() throws SQLException { final String queryString = "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" + " {[Measures].[Unit Sales]}) on 0,\n" + " {[USA].[CA].[Los Angeles],\n" + " [USA].[CA].[San Francisco]} on 1\n" + "FROM [Sales]\n" + "WHERE ([Gender].[M], [Marital Status].[S])"; assertFormat( queryString, Format.TRADITIONAL, "Axis #0:\n" + "{[Gender].[M], [Marital Status].[S]}\n" + "Axis #1:\n" + "{[Time].[1997].[Q1], [Measures].[Unit Sales]}\n" + "{[Time].[1997].[Q2].[4], [Measures].[Unit Sales]}\n" + "Axis #2:\n" + "{[Store].[USA].[CA].[Los Angeles]}\n" + "{[Store].[USA].[CA].[San Francisco]}\n" + "Row #0: 1,615\n" + "Row #0: 594\n" + "Row #1: 101\n" + "Row #1: 55\n"); // TODO: rectagular formatter should print filter assertFormat( queryString, Format.COMPACT_RECTANGULAR, " 1997 \n" + " Q1 Q2\n" + " 4\n" + " Unit Sales Unit Sales\n" + "=== == ============= ========== ==========\n" + "USA CA Los Angeles 1,615 594\n" + " San Francisco 101 55\n"); // TODO: rectagular formatter should print filter assertFormat( queryString, Format.RECTANGULAR, "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "| | Unit Sales | Unit Sales |\n" + "+-----+----+---------------+------------+------------+\n" + "| USA | CA | Los Angeles | 1,615 | 594 |\n" + "| | | San Francisco | 101 | 55 |\n"); } public void testFilterCompound() throws SQLException { final String queryString = "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" + " {[Measures].[Unit Sales]}) on 0,\n" + " {[USA].[CA].[Los Angeles],\n" + " [USA].[CA].[San Francisco]} on 1\n" + "FROM [Sales]\n" + "WHERE [Gender].Children * [Marital Status].Members"; assertFormat( queryString, Format.TRADITIONAL, "Axis #0:\n" + "{[Gender].[F], [Marital Status].[All Marital Status]}\n" + "{[Gender].[F], [Marital Status].[M]}\n" + "{[Gender].[F], [Marital Status].[S]}\n" + "{[Gender].[M], [Marital Status].[All Marital Status]}\n" + "{[Gender].[M], [Marital Status].[M]}\n" + "{[Gender].[M], [Marital Status].[S]}\n" + "Axis #1:\n" + "{[Time].[1997].[Q1], [Measures].[Unit Sales]}\n" + "{[Time].[1997].[Q2].[4], [Measures].[Unit Sales]}\n" + "Axis #2:\n" + "{[Store].[USA].[CA].[Los Angeles]}\n" + "{[Store].[USA].[CA].[San Francisco]}\n" + "Row #0: 6,373\n" + "Row #0: 1,865\n" + "Row #1: 439\n" + "Row #1: 149\n"); } public void testZeroAxesRectangular() throws SQLException { final String mdx = "select\n" + "from [Sales]\n" + "where ([Measures].[Store Sales], [Time].[1997].[Q2])"; assertFormat( mdx, Format.RECTANGULAR, "| 132,666.27 |\n"); assertFormat( mdx, Format.COMPACT_RECTANGULAR, "132,666.27\n"); } public void testOneAxisRectangular() throws SQLException { assertFormat( "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]}) on 0\n" + "FROM [Sales]", Format.RECTANGULAR, "| 1997 |\n" + "| Q1 | Q2 |\n" + "| | 4 |\n" + "| Unit Sales | Store Sales | Unit Sales | Store Sales |\n" + "+------------+-------------+------------+-------------+\n" + "| 66,291 | 139,628.35 | 20,179 | 42,878.25 |\n"); } public void testThreeAxes() throws SQLException { assertFormat( "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" + " {[Measures].[Unit Sales], [Measures].[Store Sales]}) on 0,\n" + " {[Store],\n" + " [Store].[USA],\n" + " [Store].[USA].[CA],\n" + " [Store].[USA].[CA].[Los Angeles],\n" + " [Store].[USA].[WA]} on 1,\n" + " {[Product].[Drink], [Product].[Food].[Dairy]} on 2\n" + "FROM [Sales]", Format.RECTANGULAR, "\n" + "PAGES: [Product].[Drink]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "| | Unit Sales | Store Sales | Unit Sales | Store Sales |\n" + "+------------+-----+----+-------------+------------+-------------+------------+-------------+\n" + "| All Stores | | | | 5,976 | 11,585.80 | 1,948 | 3,884.53 |\n" + "| | USA | | | 5,976 | 11,585.80 | 1,948 | 3,884.53 |\n" + "| | | CA | | 1,654 | 3,309.75 | 583 | 1,212.78 |\n" + "| | | | Los Angeles | 650 | 1,267.04 | 141 | 289.16 |\n" + "| | | WA | | 2,679 | 5,106.36 | 1,007 | 1,978.99 |\n" + "\n" + "PAGES: [Product].[Food].[Dairy]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "| | Unit Sales | Store Sales | Unit Sales | Store Sales |\n" + "+------------+-----+----+-------------+------------+-------------+------------+-------------+\n" + "| All Stores | | | | 3,262 | 7,708.75 | 1,047 | 2,512.80 |\n" + "| | USA | | | 3,262 | 7,708.75 | 1,047 | 2,512.80 |\n" + "| | | CA | | 845 | 2,004.95 | 297 | 721.34 |\n" + "| | | | Los Angeles | 288 | 708.69 | 82 | 196.59 |\n" + "| | | WA | | 1,504 | 3,544.86 | 533 | 1,275.98 |\n"); } public void testFourAxes() throws SQLException { assertFormat( "select\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]} on 0,\n" + " {[Store].[USA],\n" + " [Store].[USA].[OR]} on 1,\n" + " {[Product].[Drink], [Product].[Food].[Dairy]} on 2,\n" + " Crossjoin(\n" + " {[Marital Status].Members},\n" + " {[Gender].[F], [Gender].[M]}) on 3\n" + "FROM [Sales]\n" + "WHERE [Measures].[Store Sales]", Format.RECTANGULAR, "\n" + "CHAPTERS: [Marital Status].[All Marital Status], [Gender].[F]\n" + "PAGES: [Product].[Drink]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+----------+\n" + "| USA | | 5,676.21 | 1,836.80 |\n" + "| | OR | 1,569.00 | 327.26 |\n" + "\n" + "CHAPTERS: [Marital Status].[All Marital Status], [Gender].[F]\n" + "PAGES: [Product].[Food].[Dairy]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+----------+\n" + "| USA | | 3,873.00 | 1,378.20 |\n" + "| | OR | 1,069.88 | 284.91 |\n" + "\n" + "CHAPTERS: [Marital Status].[All Marital Status], [Gender].[M]\n" + "PAGES: [Product].[Drink]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+----------+\n" + "| USA | | 5,909.59 | 2,047.73 |\n" + "| | OR | 1,600.69 | 365.50 |\n" + "\n" + "CHAPTERS: [Marital Status].[All Marital Status], [Gender].[M]\n" + "PAGES: [Product].[Food].[Dairy]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+----------+\n" + "| USA | | 3,835.75 | 1,134.60 |\n" + "| | OR | 1,089.06 | 230.57 |\n" + "\n" + "CHAPTERS: [Marital Status].[M], [Gender].[F]\n" + "PAGES: [Product].[Drink]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+--------+\n" + "| USA | | 3,099.69 | 971.79 |\n" + "| | OR | 767.62 | 134.02 |\n" + "\n" + "CHAPTERS: [Marital Status].[M], [Gender].[F]\n" + "PAGES: [Product].[Food].[Dairy]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+--------+\n" + "| USA | | 2,125.13 | 732.95 |\n" + "| | OR | 581.31 | 160.55 |\n" + "\n" + "CHAPTERS: [Marital Status].[M], [Gender].[M]\n" + "PAGES: [Product].[Drink]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+--------+\n" + "| USA | | 2,874.11 | 914.70 |\n" + "| | OR | 643.61 | 132.37 |\n" + "\n" + "CHAPTERS: [Marital Status].[M], [Gender].[M]\n" + "PAGES: [Product].[Food].[Dairy]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+--------+\n" + "| USA | | 1,920.54 | 528.54 |\n" + "| | OR | 519.94 | 108.96 |\n" + "\n" + "CHAPTERS: [Marital Status].[S], [Gender].[F]\n" + "PAGES: [Product].[Drink]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+--------+\n" + "| USA | | 2,576.52 | 865.01 |\n" + "| | OR | 801.38 | 193.24 |\n" + "\n" + "CHAPTERS: [Marital Status].[S], [Gender].[F]\n" + "PAGES: [Product].[Food].[Dairy]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+--------+\n" + "| USA | | 1,747.87 | 645.25 |\n" + "| | OR | 488.57 | 124.36 |\n" + "\n" + "CHAPTERS: [Marital Status].[S], [Gender].[M]\n" + "PAGES: [Product].[Drink]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+----------+\n" + "| USA | | 3,035.48 | 1,133.03 |\n" + "| | OR | 957.08 | 233.13 |\n" + "\n" + "CHAPTERS: [Marital Status].[S], [Gender].[M]\n" + "PAGES: [Product].[Food].[Dairy]\n" + "| | 1997 |\n" + "| | Q1 | Q2 |\n" + "| | | 4 |\n" + "+-----+----+----------+--------+\n" + "| USA | | 1,915.21 | 606.06 |\n" + "| | OR | 569.12 | 121.61 |\n"); } } // End CellSetFormatterTest.java olap4j-1.0.1.500/testsrc/org/olap4j/transform/0000755000175000017500000000000011711470530020562 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/transform/TransformTest.java0000644000175000017500000001730711711470530024250 0ustar drazzibdrazzib/* // $Id: TransformTest.java 498 2012-01-30 16:30:42Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.*; import org.olap4j.mdx.SelectNode; import org.olap4j.mdx.parser.MdxParser; import org.olap4j.test.TestContext; import junit.framework.TestCase; import java.sql.Connection; import java.sql.SQLException; /** * Testcase for org.olap4j.transform package. * * @author etdub * @author jhyde * @version $Id: TransformTest.java 498 2012-01-30 16:30:42Z lucboudreau $ * @since Jul 28, 2008 */ public class TransformTest extends TestCase { private TestContext testContext = TestContext.instance(); private TestContext.Tester tester = testContext.getTester(); private Connection connection = null; public TransformTest() { super(); } /** * Simple strategy to prevent connection leaks: each test that needs a * connection assigns it to this field, and {@link #tearDown()} closes it * if it is not already closed. */ protected void tearDown() throws Exception { // Simple strategy to prevent connection leaks if (connection != null && !connection.isClosed()) { connection.close(); connection = null; } testContext = null; tester = null; } protected OlapConnection getConnection() throws SQLException { if (connection == null) { connection = tester.createConnection(); } return tester.getWrapper().unwrap(connection, OlapConnection.class); } protected OlapStatement getStatement() throws SQLException { return getConnection().createStatement(); } /** * Asserts the functionality of a transformation * * @param initialMdx initial MDX query to be transformed * @param expectedMdx expected MDX query after applying transform; will * be compared against the transformed query * @param trans the transformation to apply to the initial query * * @throws java.sql.SQLException on error */ public void assertTransformTo( String initialMdx, String expectedMdx, MdxQueryTransform trans) throws SQLException { OlapConnection olapConnection = getConnection(); MdxParser mdxParser = olapConnection.getParserFactory().createMdxParser(olapConnection); SelectNode before = mdxParser.parseSelect(initialMdx); SelectNode after = trans.apply(before); // we also parse the expected MDX in order to normalize it // (eliminate any whitespace / capitalization differences) // note: CallNodes are not aware of function names, and as such // will be compared in a case-sensitive manner // (i.e. [SomeMember].Children vs [SomeMember].children are not // equal, even if they are equivalent in MDX) SelectNode expected = mdxParser.parseSelect(expectedMdx); // TODO: consider adding .equals() method to ParseTreeNode instead // of comparing strings (we could ignore case when comparing // function names in CallNodes ...) assertEquals(expected.toString(), after.toString()); } /** * Unit test for DrillReplaceTransform. * * @throws java.sql.SQLException on error */ public void testDrillReplaceTransform() throws SQLException { final String initialMdx = "SELECT {[Measures].[Unit Sales], " + " [Measures].[Store Cost], " + " [Measures].[Store Sales]} ON COLUMNS, " + " {[Product].[All Products]} ON ROWS " + "FROM Sales " + "WHERE ([Time].[1997])"; final String expectedMdx = "SELECT {[Measures].[Unit Sales], " + " [Measures].[Store Cost], " + " [Measures].[Store Sales]} ON COLUMNS, " + " {[Product].[All Products].Children} ON ROWS " + "FROM Sales " + "WHERE ([Time].[1997])"; CellSet cellSet = getStatement().executeOlapQuery(initialMdx); MdxQueryTransform transform = StandardTransformLibrary.createDrillReplaceTransform( Axis.ROWS, 0, // position ordinal in axis 0, // member ordinal in position cellSet); assertTransformTo(initialMdx, expectedMdx, transform); } /** * Unit test for RollUpLevelTransform. * * @throws java.sql.SQLException on error */ public void testRollUpLevelTransform() throws SQLException { final String initialMdx = "SELECT {[Measures].[Unit Sales], " + " [Measures].[Store Cost], " + " [Measures].[Store Sales]} ON COLUMNS, " + " {[Product].[All Products].[Food].[Deli]} ON ROWS " + "FROM Sales " + "WHERE ([Time].[1997])"; final String expectedMdx = "SELECT {[Measures].[Unit Sales], " + " [Measures].[Store Cost], " + " [Measures].[Store Sales]} ON COLUMNS, " + " {[Product].[Food].[Deli].Parent.Level.Members} ON ROWS " + "FROM Sales " + "WHERE ([Time].[1997])"; CellSet cellSet = getStatement().executeOlapQuery(initialMdx); MdxQueryTransform transform = StandardTransformLibrary.createRollUpLevelTransform( Axis.ROWS, 0, // position ordinal in axis 0, // member ordinal in position cellSet); assertTransformTo(initialMdx, expectedMdx, transform); } /** * Unit test for DrillDownOnPositionTransform. * * @throws java.sql.SQLException on error */ public void _testDrillDownOnPositionTransform() throws SQLException { // TODO: rewrite the initial and expected MDX once this transform // is written. // Will fail for now. final String initialMdx = "SELECT {[Measures].[Unit Sales], " + " [Measures].[Store Cost], " + " [Measures].[Store Sales]} ON COLUMNS, " + " {[Product].[All Products]} ON ROWS " + "FROM Sales " + "WHERE ([Time].[1997])"; final String expectedMdx = "SELECT {[Measures].[Unit Sales], " + " [Measures].[Store Cost], " + " [Measures].[Store Sales]} ON COLUMNS, " + " {[Product].[All Products].Children} ON ROWS " + "FROM Sales " + "WHERE ([Time].[1997])"; CellSet cellSet = getStatement().executeOlapQuery(initialMdx); MdxQueryTransform transform = StandardTransformLibrary.createDrillDownOnPositionTransform( Axis.ROWS, 0, // position ordinal in axis 0, // member ordinal in position cellSet); assertTransformTo(initialMdx, expectedMdx, transform); } } // End TransformTest.java olap4j-1.0.1.500/testsrc/org/olap4j/XmlaConnectionTest.java0000644000175000017500000004145011713757606023215 0ustar drazzibdrazzib/* // $Id: XmlaConnectionTest.java 498 2012-01-30 16:30:42Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.driver.xmla.XmlaOlap4jDriver; import org.olap4j.driver.xmla.XmlaOlap4jServerInfos; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxyException; import org.olap4j.test.TestContext; import org.olap4j.test.TestContext.Tester; import junit.framework.TestCase; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.*; import java.util.concurrent.Future; /** * Unit test for XMLA driver connections. * * @version $Id: XmlaConnectionTest.java 498 2012-01-30 16:30:42Z lucboudreau $ */ public class XmlaConnectionTest extends TestCase { private TestContext testContext = TestContext.instance(); private TestContext.Tester tester = testContext.getTester(); public static final String DRIVER_CLASS_NAME = "org.olap4j.driver.xmla.XmlaOlap4jDriver"; static class XmlaOlap4jProxyMock implements XmlaOlap4jProxy { public byte[] get( XmlaOlap4jServerInfos serverInfos, String request) { throw new RuntimeException("Non-Trivial Call!"); } public String getEncodingCharsetName() { return "UTF-8"; } public Future submit( XmlaOlap4jServerInfos serverInfos, String request) { throw new RuntimeException("Non-Trivial Call!"); } } /** * Implementation of {@link org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy} * that delegates all requests to an underlying proxy. */ public static class DelegatingTestProxy implements XmlaOlap4jProxy { protected final XmlaOlap4jProxy proxy; /** * Creates a DelegatingTestProxy. * * @param proxy Underlying proxy */ public DelegatingTestProxy(XmlaOlap4jProxy proxy) { this.proxy = proxy; } public byte[] get(XmlaOlap4jServerInfos serverInfos, String request) throws XmlaOlap4jProxyException { return proxy.get(serverInfos, request); } public Future submit( XmlaOlap4jServerInfos serverInfos, String request) { return proxy.submit(serverInfos, request); } public String getEncodingCharsetName() { return proxy.getEncodingCharsetName(); } } /** * Proxy that checks that the same request does not occur twice. */ public static class DoubleSubmissionTestProxy extends DelegatingTestProxy { final Map requests = new HashMap(); private static String PROXY_CLASS_NAME; /** * Creates a DoubleSubmissionTestProxy. * *

Public constructor is required because this is instantiated via * reflection. * *

Instantiates an underlying proxy whose name is given by * {@link #getProxyClassName()}. * * @param catalogNameUrls Collection of catalog names and the URL where * their catalog is to be found. For testing purposes, this should * contain a catalog called "FoodMart". * * @param urlString JDBC connect string; must begin with * "jdbc:mondrian:" */ public DoubleSubmissionTestProxy( Map catalogNameUrls, String urlString) { super(createProxy(catalogNameUrls, urlString)); } /** * Sets the name of the class which is the underlying proxy. * * @param clazz Proxy class name */ public static void setProxyClassName(String clazz) { PROXY_CLASS_NAME = clazz; } /** * Returns the name of the class which is the underlying proxy. * * @return Proxy class name */ public static String getProxyClassName() { return PROXY_CLASS_NAME; } /** * Creates the underlying proxy. * * @param catalogNameUrls Catalog name URLs * @param urlString URL * @return Proxy */ static XmlaOlap4jProxy createProxy( Map catalogNameUrls, String urlString) { try { final Class clazz = Class.forName(getProxyClassName()); final Constructor constructor = clazz.getConstructor(Map.class, String.class); return (XmlaOlap4jProxy) constructor.newInstance( catalogNameUrls, urlString); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } public byte[] get(XmlaOlap4jServerInfos serverInfos, String request) throws XmlaOlap4jProxyException { this.checkup(request); return super.get(serverInfos, request); } /** * Checks that a request has not been seen before. * * @param request Request * * @throws RuntimeException if proxy has been seen before */ private void checkup(String request) { String hash = Encoder.convertToHex(request.getBytes()); if (request.indexOf("MDSCHEMA_CUBES") == -1 && this.requests.containsKey(hash)) { throw new RuntimeException("DOUBLE-REQUEST"); } else { this.requests.put(hash, request); } } } protected void tearDown() throws Exception { testContext = null; tester = null; super.tearDown(); } /** * Verifies that the construction of the necessary * XMLA objects during DriverManager.getConnection() do not make * calls that could cause deadlocks. */ public void testNoNonTrivalCallsOnConnect() throws Exception { String cookie = XmlaOlap4jDriver.nextCookie(); try { XmlaOlap4jDriver.PROXY_MAP.put(cookie, new XmlaOlap4jProxyMock()); try { Class.forName(DRIVER_CLASS_NAME); } catch (ClassNotFoundException e) { throw new RuntimeException("oops", e); } Properties info = new Properties(); info.setProperty( XmlaOlap4jDriver.Property.CATALOG.name(), "FoodMart"); DriverManager.getConnection( "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie, info); } catch (Throwable t) { t.printStackTrace(); fail( "Non-Trival Call executed during construction of XmlaOlap4j " + "Connection"); } } public void testDbSchemaSchemata() throws Exception { if (!testContext.getTester().getFlavor() .equals(Tester.Flavor.XMLA)) { return; } class Proxy extends DoubleSubmissionTestProxy { boolean schemata = false; boolean cubes = false; public Proxy( Map catalogNameUrls, String urlString) { super(catalogNameUrls, urlString); } @Override public byte[] get( XmlaOlap4jServerInfos serverInfos, String request) throws XmlaOlap4jProxyException { if (request.contains("DBSCHEMA_SCHEMATA")) { if (schemata || cubes) { fail(); } schemata = true; } else if (request.contains("MDSCHEMA_CUBES")) { if (!schemata || cubes) { fail(); } } return super.get(serverInfos, request); } } String oldValue = XmlaTester.getProxyClassName(); XmlaTester.setProxyClassName( Proxy.class.getName()); DoubleSubmissionTestProxy.setProxyClassName(oldValue); try { Connection connection = tester.createConnection(); OlapConnection oConn = tester.getWrapper().unwrap(connection, OlapConnection.class); oConn.getOlapSchema().getCubes().size(); } finally { XmlaTester.setProxyClassName(oldValue); } } /** * Tests that no request is sent to XMLA more than once. * If the same request is sent twice, throws an exception. The only * exception to this is the MDSCHEMA_CUBES query that is used to * populate both the catalogs and the schemas associated to a * given catalog. This was due to a flaw in SSAS; it doesn't * return a SCHEMA_NAME column when asked to. We fixed it this * way in some other revision. * @throws Exception If the test fails. */ public void testNoDoubleQuerySubmission() throws Exception { if (!testContext.getTester().getFlavor() .equals(Tester.Flavor.XMLA) && !testContext.getTester().getFlavor() .equals(Tester.Flavor.REMOTE_XMLA)) { return; } String oldValue = XmlaTester.getProxyClassName(); XmlaTester.setProxyClassName( DoubleSubmissionTestProxy.class.getName()); DoubleSubmissionTestProxy.setProxyClassName(oldValue); try { Connection connection = tester.createConnection(); Statement statement = connection.createStatement(); final OlapStatement olapStatement = tester.getWrapper().unwrap(statement, OlapStatement.class); CellSet cellSet = olapStatement.executeOlapQuery( "SELECT\n" + " {[Measures].[Unit Sales],\n" + " [Measures].[Store Sales]} ON COLUMNS\n," + " Crossjoin({[Gender].[M]}, [Product].Children) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q2]"); assertNotNull(cellSet); cellSet = olapStatement.executeOlapQuery( "SELECT\n" + " {[Measures].[Unit Sales],\n" + " [Measures].[Store Sales]} ON COLUMNS\n," + " Crossjoin({[Gender].[M]}, [Product].Children) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q3]"); } finally { XmlaTester.setProxyClassName(oldValue); } } /** * This is a test to verify that server specific properties * can be sent to the server in the PropertyList element * of SOAP messages. A property that is not part of those enumerated * in {@link org.olap4j.driver.xmla.XmlaOlap4jDriver.Property} must * not be sent to the server. */ public void testPropertyList() throws Exception { if (!testContext.getTester().getFlavor() .equals(Tester.Flavor.XMLA) && !testContext.getTester().getFlavor() .equals(Tester.Flavor.REMOTE_XMLA)) { return; } switch (testContext.getTester().getWrapper()) { case DBCP: return; } final String oldValue = XmlaTester.getProxyClassName(); try { XmlaTester.setProxyClassName( PropertyListTestProxy.class.getName()); OlapConnection connection = tester.getWrapper().unwrap( tester.createConnection(), OlapConnection.class); OlapStatement olapStatement = connection.createStatement(); olapStatement.executeOlapQuery( "SELECT\n" + " {[Measures].[Unit Sales],\n" + " [Measures].[Store Sales]} ON COLUMNS\n," + " Crossjoin({[Gender].[M]}, [Product].Children) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q2]"); assertEquals(0, PropertyListTestProxy.count); connection.close(); connection = tester.getWrapper().unwrap( tester.createConnectionWithUserPassword(), OlapConnection.class); olapStatement = connection.createStatement(); olapStatement.executeOlapQuery( "SELECT\n" + " {[Measures].[Unit Sales],\n" + " [Measures].[Store Sales]} ON COLUMNS\n," + " Crossjoin({[Gender].[M]}, [Product].Children) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q2]"); assertEquals(0, PropertyListTestProxy.count); connection.close(); final Properties props = new Properties(); props.put("FOOBAR", "Bacon"); connection = tester.getWrapper().unwrap( ((XmlaTester)tester) .createConnectionWithUserPassword(props), OlapConnection.class); olapStatement = connection.createStatement(); try { olapStatement.executeOlapQuery( "SELECT\n" + " {[Measures].[Unit Sales],\n" + " [Measures].[Store Sales]} ON COLUMNS\n," + " Crossjoin({[Gender].[M]}, [Product].Children) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Time].[1997].[Q2]"); } catch (Throwable e) { assertTrue(e.getCause().getMessage().contains("FOOBAR")); } connection.close(); } finally { XmlaTester.setProxyClassName(oldValue); } } /** * This is a class for the test * {@link XmlaConnectionTest#testPropertyList()}. */ public static class PropertyListTestProxy extends DelegatingTestProxy { public PropertyListTestProxy(XmlaOlap4jProxy proxy) { super(proxy); } private final static String[] lookup = new String[] { "" }; private static int count = 0; public byte[] get( XmlaOlap4jServerInfos serverInfos, String request) throws XmlaOlap4jProxyException { for (String token : lookup) { if (request.contains(token)) { count++; } } return super.get(serverInfos, request); } } private static class Encoder { /** * Converts an array of bytes to a hex string. * *

For example, convertToHex(new byte[] {(byte) 0xDE, * (byte) 0xAD}) returns "DEAD". * * @param data Array of bytes * @return Bytes encoded as hex */ private static String convertToHex(byte[] data) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < data.length; i++) { int halfbyte = (data[i] >>> 4) & 0x0F; int two_halfs = 0; do { if ((0 <= halfbyte) && (halfbyte <= 9)) { buf.append((char) ('0' + halfbyte)); } else { buf.append((char) ('a' + (halfbyte - 10))); } halfbyte = data[i] & 0x0F; } while (two_halfs++ < 1); } return buf.toString(); } } } // End XmlaConnectionTest.java olap4j-1.0.1.500/testsrc/org/olap4j/MetadataTest.java0000644000175000017500000011541011711470530021774 0ustar drazzibdrazzib/* // $Id: MetadataTest.java 498 2012-01-30 16:30:42Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; import org.olap4j.test.TestContext; import junit.framework.TestCase; import java.sql.*; import java.util.*; /** * Unit test for olap4j metadata methods. * * @version $Id: MetadataTest.java 498 2012-01-30 16:30:42Z lucboudreau $ */ public class MetadataTest extends TestCase { private TestContext testContext = TestContext.instance(); private TestContext.Tester tester = testContext.getTester(); private static final String NL = System.getProperty("line.separator"); private Connection connection; private String catalogName; private OlapConnection olapConnection; private OlapDatabaseMetaData olapDatabaseMetaData; private final String propertyNamePattern = null; private final String dataSourceName = "xx"; private static final List CUBE_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "CUBE_TYPE", "CUBE_GUID", "CREATED_ON", "LAST_SCHEMA_UPDATE", "SCHEMA_UPDATED_BY", "LAST_DATA_UPDATE", "DATA_UPDATED_BY", "IS_DRILLTHROUGH_ENABLED", "IS_WRITE_ENABLED", "IS_LINKABLE", "IS_SQL_ENABLED", "DESCRIPTION"); private static final List LITERALS_COLUMN_NAMES = Arrays.asList( "LITERAL_NAME", "LITERAL_VALUE", "LITERAL_INVALID_CHARS", "LITERAL_INVALID_STARTING_CHARS", "LITERAL_MAX_LENGTH"); private static final List SETS_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "SET_NAME", "SCOPE"); private static final List PROPERTIES_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_UNIQUE_NAME", "MEMBER_UNIQUE_NAME", "PROPERTY_NAME", "PROPERTY_CAPTION", "PROPERTY_TYPE", "DATA_TYPE", "PROPERTY_CONTENT_TYPE", "DESCRIPTION"); private static final List MEMBERS_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_UNIQUE_NAME", "LEVEL_NUMBER", "MEMBER_ORDINAL", "MEMBER_NAME", "MEMBER_UNIQUE_NAME", "MEMBER_TYPE", "MEMBER_GUID", "MEMBER_CAPTION", "CHILDREN_CARDINALITY", "PARENT_LEVEL", "PARENT_UNIQUE_NAME", "PARENT_COUNT", "TREE_OP", "DEPTH"); private static final List MEASURES_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "MEASURE_NAME", "MEASURE_UNIQUE_NAME", "MEASURE_CAPTION", "MEASURE_GUID", "MEASURE_AGGREGATOR", "DATA_TYPE", "MEASURE_IS_VISIBLE", "LEVELS_LIST", "DESCRIPTION"); private static final List LEVELS_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_NAME", "LEVEL_UNIQUE_NAME", "LEVEL_GUID", "LEVEL_CAPTION", "LEVEL_NUMBER", "LEVEL_CARDINALITY", "LEVEL_TYPE", "CUSTOM_ROLLUP_SETTINGS", "LEVEL_UNIQUE_SETTINGS", "LEVEL_IS_VISIBLE", "DESCRIPTION"); private static final List HIERARCHIES_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_NAME", "HIERARCHY_UNIQUE_NAME", "HIERARCHY_GUID", "HIERARCHY_CAPTION", "DIMENSION_TYPE", "HIERARCHY_CARDINALITY", "DEFAULT_MEMBER", "ALL_MEMBER", "DESCRIPTION", "STRUCTURE", "IS_VIRTUAL", "IS_READWRITE", "DIMENSION_UNIQUE_SETTINGS", "DIMENSION_IS_VISIBLE", "HIERARCHY_IS_VISIBLE", "HIERARCHY_ORDINAL", "DIMENSION_IS_SHARED", "PARENT_CHILD"); private static final List FUNCTIONS_COLUMN_NAMES = Arrays.asList( "FUNCTION_NAME", "DESCRIPTION", "PARAMETER_LIST", "RETURN_TYPE", "ORIGIN", "INTERFACE_NAME", "LIBRARY_NAME", "CAPTION"); private static final List DIMENSIONS_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_NAME", "DIMENSION_UNIQUE_NAME", "DIMENSION_GUID", "DIMENSION_CAPTION", "DIMENSION_ORDINAL", "DIMENSION_TYPE", "DIMENSION_CARDINALITY", "DEFAULT_HIERARCHY", "DESCRIPTION", "IS_VIRTUAL", "IS_READWRITE", "DIMENSION_UNIQUE_SETTINGS", "DIMENSION_MASTER_UNIQUE_NAME", "DIMENSION_IS_VISIBLE"); private static final List DATABASE_PROPERTIES_COLUMN_NAMES = Arrays.asList( "PROPERTY_NAME", "PROPERTY_DESCRIPTION", "PROPERTY_TYPE", "PROPERTY_ACCESS_TYPE", "IS_REQUIRED", "PROPERTY_VALUE"); private static final List DATASOURCES_COLUMN_NAMES = Arrays.asList( "DATA_SOURCE_NAME", "DATA_SOURCE_DESCRIPTION", "URL", "DATA_SOURCE_INFO", "PROVIDER_NAME", "PROVIDER_TYPE", "AUTHENTICATION_MODE"); private static final List CATALOGS_COLUMN_NAMES = Arrays.asList( "TABLE_CAT"); private static final List SCHEMAS_COLUMN_NAMES = Arrays.asList( "TABLE_SCHEM", "TABLE_CAT"); private static final List ACTIONS_COLUMN_NAMES = Arrays.asList( "CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "ACTION_NAME", "COORDINATE", "COORDINATE_TYPE"); public MetadataTest() throws SQLException { } protected void setUp() throws SQLException { connection = tester.createConnection(); catalogName = connection.getCatalog(); olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); olapDatabaseMetaData = olapConnection.getMetaData(); } protected void tearDown() throws Exception { if (connection != null && !connection.isClosed()) { connection.close(); connection = null; } connection = null; olapConnection = null; olapDatabaseMetaData = null; testContext = null; tester = null; } // ~ Helper methods ---------- private void assertContains(String seek, String s) { if (s.indexOf(seek) < 0) { fail("expected to find '" + seek + "' in '" + s + "'"); } } private void assertContainsLine(String partial, String seek, String s) { if (partial == null) { partial = seek; } int i = s.indexOf(partial); if (i < 0) { fail("expected to find '" + seek + "' in '" + s + "'"); } int start = i; while (start > 0 && s.charAt(start - 1) != 0x0D && s.charAt(start - 1) != 0x0A) { --start; } int end = i; while (end < s.length() && s.charAt(end) != 0x0D && s.charAt(end) != 0x0A) { ++end; } String line = s.substring(start, end); assertEquals(seek, line); } private void assertNotContains(String seek, String s) { if (s.indexOf(seek) >= 0) { fail("expected not to find '" + seek + "' in '" + s + "'"); } } private int linecount(String s) { int i = 0; int count = 0; while (i < s.length()) { int nl = s.indexOf('\n', i); if (nl < 0) { break; } i = nl + 1; ++count; } return count; } // ~ Tests follow ------------- public void testDatabaseMetaData() throws SQLException { assertEquals("" + catalogName + "", catalogName); DatabaseMetaData databaseMetaData = connection.getMetaData(); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: // FIXME: implement getDatabaseXxxVersion in XMLA driver break; default: assertTrue(databaseMetaData.getDatabaseMajorVersion() > 0); assertTrue(databaseMetaData.getDatabaseMinorVersion() >= 0); // assertTrue(databaseMetaData.getDatabaseProductName() != null); assertTrue(databaseMetaData.getDatabaseProductVersion() != null); break; } assertTrue(databaseMetaData.getDriverName() != null); assertTrue(databaseMetaData.getDriverVersion() != null); // mondrian-specific switch (tester.getFlavor()) { case MONDRIAN: assertTrue(databaseMetaData.isReadOnly()); assertNull(databaseMetaData.getUserName()); assertNotNull(databaseMetaData.getURL()); break; } // unwrap connection; may or may not be the same object as connection; // check extended methods // also unwrap metadata from regular connection assertTrue( ((OlapWrapper) databaseMetaData).isWrapperFor( OlapDatabaseMetaData.class)); assertFalse( ((OlapWrapper) databaseMetaData).isWrapperFor( OlapStatement.class)); OlapDatabaseMetaData olapDatabaseMetaData1 = ((OlapWrapper) databaseMetaData).unwrap( OlapDatabaseMetaData.class); assertTrue( olapDatabaseMetaData1.getDriverName().equals( olapDatabaseMetaData.getDriverName())); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: // FIXME: implement getDatabaseXxxVersion in XMLA driver break; default: assertTrue( olapDatabaseMetaData1.getDatabaseProductVersion().equals( olapDatabaseMetaData.getDatabaseProductVersion())); } } public void testSchemas() throws OlapException { // check schema auto detection final Schema schema1 = olapConnection.getOlapSchema(); assertEquals( "Failed to auto detect the schema.", schema1.getName(), "FoodMart"); switch (tester.getFlavor()) { case MONDRIAN: // Setting a correct schema should work. olapConnection.setSchema("FoodMart"); // setting a null schema should be ignored olapConnection.setSchema(null); // setting a non existent schema should be ignored olapConnection.setSchema("Chunky Bacon"); break; case XMLA: case REMOTE_XMLA: // Setting a correct schema should work. olapConnection.setSchema(catalogName); // setting a null schema should fail try { olapConnection.setSchema(null); fail(); } catch (OlapException e) { // no op. } // setting a non existent schema should fail try { olapConnection.setSchema("Chunky Bacon"); fail(); } catch (OlapException e) { // no op. } break; default: fail("Unknown tester flavor."); } } public void testCatalogs() throws SQLException { final Catalog catalog = olapConnection.getOlapCatalog(); assertEquals( "Failed to auto detect the catalog.", catalog.getName(), "FoodMart"); switch (tester.getFlavor()) { case MONDRIAN: // Setting a correct catalog should work. olapConnection.setCatalog("FoodMart"); // setting a null catalog should be ignored olapConnection.setCatalog(null); // setting a non existent catalog should be ignored olapConnection.setCatalog("Chunky Bacon"); break; case XMLA: case REMOTE_XMLA: // Setting a correct catalog should work. olapConnection.setCatalog(catalogName); // setting a null catalog should fail try { olapConnection.setCatalog(null); fail(); } catch (OlapException e) { // no op. } // setting a non existent catalog should fail try { olapConnection.setCatalog("Chunky Bacon"); fail(); } catch (OlapException e) { // no op. } break; default: fail("Unknown tester flavor."); } } public void testDatabases() throws SQLException { final Database database = olapConnection.getOlapDatabase(); assertTrue( "Failed to auto detect the database.", database.getName() .equals("Provider=Mondrian;DataSource=MondrianFoodMart;") || database.getName() .equals("FoodMart")); switch (tester.getFlavor()) { case MONDRIAN: // Setting a correct database should work. olapConnection.setDatabase("FoodMart"); // setting a null database should be ignored olapConnection.setDatabase(null); // setting a non existent database should be ignored olapConnection.setDatabase("Chunky Bacon"); break; case XMLA: // Setting a correct database should work. olapConnection.setDatabase( "FoodMart"); // setting a null database should fail try { olapConnection.setDatabase(null); fail(); } catch (OlapException e) { // no op. } // setting a non existent database should fail try { olapConnection.setDatabase("Chunky Bacon"); fail(); } catch (OlapException e) { // no op. } break; case REMOTE_XMLA: // Setting a correct database should work. olapConnection.setDatabase( "Provider=Mondrian;DataSource=MondrianFoodMart;"); // setting a null database should fail try { olapConnection.setDatabase(null); fail(); } catch (OlapException e) { // no op. } // setting a non existent database should fail try { olapConnection.setDatabase("Chunky Bacon"); fail(); } catch (OlapException e) { // no op. } break; default: fail("Unknown tester flavor."); } } public void testDatabaseMetaDataGetActions() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getActions( catalogName, null, null, null), ACTIONS_COLUMN_NAMES); assertEquals("", s); // mondrian has no actions } public void testDatabaseMetaDataGetDatasources() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getDatabases(), DATASOURCES_COLUMN_NAMES); switch (tester.getFlavor()) { case MONDRIAN: TestContext.assertEqualsVerbose( "DATA_SOURCE_NAME=FoodMart," + " DATA_SOURCE_DESCRIPTION=null," + " URL=null," + " DATA_SOURCE_INFO=FoodMart," + " PROVIDER_NAME=Mondrian," + " PROVIDER_TYPE=MDP," + " AUTHENTICATION_MODE=Unauthenticated\n", s); break; case REMOTE_XMLA: // This can be anything, depending on the remote server. break; case XMLA: TestContext.assertEqualsVerbose( "DATA_SOURCE_NAME=FoodMart," + " DATA_SOURCE_DESCRIPTION=Mondrian FoodMart data source," + " URL=http://localhost:8080/mondrian/xmla," + " DATA_SOURCE_INFO=FoodMart," + " PROVIDER_NAME=Mondrian," + " PROVIDER_TYPE=MDP," + " AUTHENTICATION_MODE=Unauthenticated\n", s); break; } } public void testDatabaseMetaDataGetCatalogs() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getCatalogs(), CATALOGS_COLUMN_NAMES); final String expected; switch (tester.getFlavor()) { case XMLA: // XMLA test uses dummy duplicate catalog to make sure that we // get all catalogs expected = "TABLE_CAT=" + catalogName + "\n" + "TABLE_CAT=" + catalogName + "2\n"; break; case REMOTE_XMLA: default: expected = "TABLE_CAT=" + catalogName + "\n"; break; } TestContext.assertEqualsVerbose(expected, s); } public void testDatabaseMetaDataGetSchemas() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getSchemas(), SCHEMAS_COLUMN_NAMES); final String expected; switch (tester.getFlavor()) { case XMLA: // XMLA test uses dummy duplicate schema to make sure that we // get all schemas expected = "TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "\n" + "TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "2\n"; break; case REMOTE_XMLA: default: expected = "TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "\n"; break; } TestContext.assertEqualsVerbose(expected, s); } public void testDatabaseMetaDataGetLiterals() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getLiterals(), LITERALS_COLUMN_NAMES); assertContains("LITERAL_NAME=DBLITERAL_QUOTE, LITERAL_VALUE=[, ", s); } public void testDatabaseMetaDataGetDatabaseProperties() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getDatabaseProperties( dataSourceName, propertyNamePattern), DATABASE_PROPERTIES_COLUMN_NAMES); assertContains("PROPERTY_NAME=ProviderName, ", s); } public void testDatabaseMetaDataGetProperties() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getProperties( catalogName, null, null, null, null, null, null, null), PROPERTIES_COLUMN_NAMES); assertContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse and Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_UNIQUE_NAME=[Store], LEVEL_UNIQUE_NAME=[Store].[Store Name], MEMBER_UNIQUE_NAME=null, PROPERTY_NAME=Frozen Sqft, PROPERTY_CAPTION=Frozen Sqft, PROPERTY_TYPE=1, DATA_TYPE=5, PROPERTY_CONTENT_TYPE=0, DESCRIPTION=Warehouse and Sales Cube - Store Hierarchy - Store Name Level - Frozen Sqft Property", s); assertEquals(s, 66, linecount(s)); s = checkResultSet( olapDatabaseMetaData.getProperties( catalogName, "FoodMart", "Sales", null, null, "[Store].[Store Name]", null, null), PROPERTIES_COLUMN_NAMES); assertContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_UNIQUE_NAME=[Store], LEVEL_UNIQUE_NAME=[Store].[Store Name], MEMBER_UNIQUE_NAME=null, PROPERTY_NAME=Has coffee bar, PROPERTY_CAPTION=Has coffee bar, PROPERTY_TYPE=1, DATA_TYPE=11, PROPERTY_CONTENT_TYPE=0, DESCRIPTION=Sales Cube - Store Hierarchy - Store Name Level - Has coffee bar Property", s); assertNotContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse and Sales, ", s); assertEquals(8, linecount(s)); } public void testDatabaseMetaDataGetMdxKeywords() throws SQLException { String keywords = olapDatabaseMetaData.getMdxKeywords(); assertNotNull(keywords); assertContains(",From,", keywords); } public void testDatabaseMetaDataGetCubes() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getCubes( catalogName, null, null), CUBE_COLUMN_NAMES); assertContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, ", s); final int lineCount = linecount(s); // Null catalog specified in metadata request, but connection has a // catalog. Should return all cubes, ignoring the connection's catalog. olapDatabaseMetaData.getConnection().setCatalog(catalogName); s = checkResultSet( olapDatabaseMetaData.getCubes( null, null, null), CUBE_COLUMN_NAMES); assertContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, ", s); final int lineCount3 = linecount(s); if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA) { assertEquals(lineCount * 2, lineCount3); } s = checkResultSet( olapDatabaseMetaData.getCubes( "FoodMart", "FoodMart", "Sales"), CUBE_COLUMN_NAMES); switch (testContext.getTester().getFlavor()) { case MONDRIAN: assertTrue(s.contains(", IS_DRILLTHROUGH_ENABLED=true")); break; case XMLA: case REMOTE_XMLA: assertTrue(s.contains(", IS_DRILLTHROUGH_ENABLED=false")); assertFalse(s.contains(", IS_DRILLTHROUGH_ENABLED=true")); break; default: throw new RuntimeException("Unknown tester type."); } // If we ask for 'Warehouse and Sales' cube we should get it, but // nothing else. s = checkResultSet( olapDatabaseMetaData.getCubes( catalogName, null, "Warehouse and Sales"), CUBE_COLUMN_NAMES); assertContains(", CUBE_NAME=Warehouse and Sales,", s); assertNotContains(", CUBE_NAME=Warehouse,", s); // If we ask for a pattern, should get multiple hits. s = checkResultSet( olapDatabaseMetaData.getCubes( catalogName, null, "Warehouse%"), CUBE_COLUMN_NAMES); assertTrue(s.contains(", CUBE_NAME=Warehouse and Sales")); assertTrue(s.contains(", CUBE_NAME=Warehouse")); assertFalse(s.contains(", CUBE_NAME=Sales")); } public void testDatabaseMetaDataGetDimensions() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getDimensions( catalogName, null, null, null), DIMENSIONS_COLUMN_NAMES); assertContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_NAME=Education Level, DIMENSION_UNIQUE_NAME=[Education Level], DIMENSION_GUID=null, DIMENSION_CAPTION=Education Level, DIMENSION_ORDINAL=9, DIMENSION_TYPE=3, DIMENSION_CARDINALITY=6, DEFAULT_HIERARCHY=[Education Level], DESCRIPTION=Sales Cube - Education Level Dimension, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_MASTER_UNIQUE_NAME=null, DIMENSION_IS_VISIBLE=true", s); assertEquals(68, linecount(s)); } public void testDatabaseMetaDataGetFunctions() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getOlapFunctions(null), FUNCTIONS_COLUMN_NAMES); assertContains( "FUNCTION_NAME=Name, DESCRIPTION=Returns the name of a member., PARAMETER_LIST=Member, RETURN_TYPE=8, ORIGIN=1, INTERFACE_NAME=, LIBRARY_NAME=null, CAPTION=Name", s); // Mondrian has 361 functions (as of 2008/1/23) final int functionCount = linecount(s); assertTrue(functionCount + " functions", functionCount > 360); // Mondrian has 13 variants of the Ascendants and Descendants functions s = checkResultSet( olapDatabaseMetaData.getOlapFunctions("%scendants"), FUNCTIONS_COLUMN_NAMES); assertEquals(s, 13, linecount(s)); } public void testDatabaseMetaDataGetHierarchies() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getHierarchies( catalogName, null, null, null, null), HIERARCHIES_COLUMN_NAMES); assertContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=HR, DIMENSION_UNIQUE_NAME=[Employees], HIERARCHY_NAME=Employees, HIERARCHY_UNIQUE_NAME=[Employees], HIERARCHY_GUID=null, HIERARCHY_CAPTION=Employees, DIMENSION_TYPE=3, HIERARCHY_CARDINALITY=1156, DEFAULT_MEMBER=[Employees].[All Employees], ALL_MEMBER=[Employees].[All Employees], DESCRIPTION=HR Cube - Employees Hierarchy, STRUCTURE=0, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_IS_VISIBLE=true, HIERARCHY_IS_VISIBLE=true, HIERARCHY_ORDINAL=7, DIMENSION_IS_SHARED=true, PARENT_CHILD=true", s); s = checkResultSet( olapDatabaseMetaData.getHierarchies( catalogName, null, "Sales", null, "Store"), HIERARCHIES_COLUMN_NAMES); TestContext.assertEqualsVerbose( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_NAME=Store, HIERARCHY_UNIQUE_NAME=[Store], HIERARCHY_GUID=null, HIERARCHY_CAPTION=Store, DIMENSION_TYPE=3, HIERARCHY_CARDINALITY=63, DEFAULT_MEMBER=[Store].[All Stores], ALL_MEMBER=[Store].[All Stores], DESCRIPTION=Sales Cube - Store Hierarchy, STRUCTURE=0, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_IS_VISIBLE=true, HIERARCHY_IS_VISIBLE=true, HIERARCHY_ORDINAL=1, DIMENSION_IS_SHARED=true, PARENT_CHILD=false\n", s); // With dimension unique name (bug 2527862). s = checkResultSet( olapDatabaseMetaData.getHierarchies( catalogName, null, "Sales", "[Store]", null), HIERARCHIES_COLUMN_NAMES); TestContext.assertEqualsVerbose( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_NAME=Store, HIERARCHY_UNIQUE_NAME=[Store], HIERARCHY_GUID=null, HIERARCHY_CAPTION=Store, DIMENSION_TYPE=3, HIERARCHY_CARDINALITY=63, DEFAULT_MEMBER=[Store].[All Stores], ALL_MEMBER=[Store].[All Stores], DESCRIPTION=Sales Cube - Store Hierarchy, STRUCTURE=0, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_IS_VISIBLE=true, HIERARCHY_IS_VISIBLE=true, HIERARCHY_ORDINAL=1, DIMENSION_IS_SHARED=true, PARENT_CHILD=false\n", s); } public void testDatabaseMetaDataGetLevels() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getLevels( catalogName, null, null, null, null, null), LEVELS_COLUMN_NAMES); assertContains( "CATALOG_NAME=FoodMart, SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Measures], HIERARCHY_UNIQUE_NAME=[Measures], LEVEL_NAME=MeasuresLevel, LEVEL_UNIQUE_NAME=[Measures].[MeasuresLevel], LEVEL_GUID=null, LEVEL_CAPTION=MeasuresLevel, LEVEL_NUMBER=0, LEVEL_CARDINALITY=9, LEVEL_TYPE=0, CUSTOM_ROLLUP_SETTINGS=0, LEVEL_UNIQUE_SETTINGS=0, LEVEL_IS_VISIBLE=true, DESCRIPTION=Sales Cube - Measures Hierarchy - MeasuresLevel Level", s); s = checkResultSet( olapDatabaseMetaData.getLevels( catalogName, null, "Sales", null, "[Store]", null), LEVELS_COLUMN_NAMES); assertEquals(s, 5, linecount(s)); } public void testDatabaseMetaDataGetLiterals2() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getLiterals(), LITERALS_COLUMN_NAMES); assertContains( "LITERAL_NAME=DBLITERAL_QUOTE, LITERAL_VALUE=[, LITERAL_INVALID_CHARS=null, LITERAL_INVALID_STARTING_CHARS=null, LITERAL_MAX_LENGTH=-1", s); assertEquals(17, linecount(s)); } public void testDatabaseMetaDataGetMeasures() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getMeasures( catalogName, null, null, null, null), MEASURES_COLUMN_NAMES); assertContains( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, MEASURE_NAME=Profit, MEASURE_UNIQUE_NAME=[Measures].[Profit], MEASURE_CAPTION=Profit, MEASURE_GUID=null, MEASURE_AGGREGATOR=127, DATA_TYPE=130, MEASURE_IS_VISIBLE=true, LEVELS_LIST=null, DESCRIPTION=Sales Cube - Profit Member", s); // wildcard match s = checkResultSet( olapDatabaseMetaData.getMeasures( catalogName, null, "Sales", "%Sales", null), MEASURES_COLUMN_NAMES); assertEquals(s, 3, linecount(s)); // wildcard match s = checkResultSet( olapDatabaseMetaData.getMeasures( catalogName, null, "Sales", null, "[Measures].[Unit Sales]"), MEASURES_COLUMN_NAMES); assertEquals(s, 1, linecount(s)); } public void testDatabaseMetaDataGetMembers() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getMembers( catalogName, "FoodMart", "Sales", null, "[Gender]", null, null, null), MEMBERS_COLUMN_NAMES); TestContext.assertEqualsVerbose( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Gender, MEMBER_UNIQUE_NAME=[Gender].[All Gender], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Gender, CHILDREN_CARDINALITY=2, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[Gender], LEVEL_NUMBER=1, MEMBER_ORDINAL=1, MEMBER_NAME=F, MEMBER_UNIQUE_NAME=[Gender].[F], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=F, CHILDREN_CARDINALITY=0, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Gender].[All Gender], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[Gender], LEVEL_NUMBER=1, MEMBER_ORDINAL=2, MEMBER_NAME=M, MEMBER_UNIQUE_NAME=[Gender].[M], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=M, CHILDREN_CARDINALITY=0, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Gender].[All Gender], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n", s); // by member unique name s = checkResultSet( olapDatabaseMetaData.getMembers( catalogName, "FoodMart", "Sales", null, null, null, "[Time].[1997].[Q2].[4]", null), MEMBERS_COLUMN_NAMES); TestContext.assertEqualsVerbose( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Time], HIERARCHY_UNIQUE_NAME=[Time], LEVEL_UNIQUE_NAME=[Time].[Month], LEVEL_NUMBER=2, MEMBER_ORDINAL=6, MEMBER_NAME=4, MEMBER_UNIQUE_NAME=[Time].[1997].[Q2].[4], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=4, CHILDREN_CARDINALITY=0, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Time].[1997].[Q2], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n", s); // with treeop s = checkResultSet( olapDatabaseMetaData.getMembers( catalogName, "FoodMart", "Sales", null, null, null, "[Customers].[USA].[CA]", Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.SIBLINGS)), MEMBERS_COLUMN_NAMES); switch (tester.getFlavor()) { case MONDRIAN: // TODO: fix mondrian driver so that members are returned sorted // by level depth TestContext.assertEqualsVerbose( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=7235, MEMBER_NAME=OR, MEMBER_UNIQUE_NAME=[Customers].[USA].[OR], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=OR, CHILDREN_CARDINALITY=11, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=8298, MEMBER_NAME=WA, MEMBER_UNIQUE_NAME=[Customers].[USA].[WA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=WA, CHILDREN_CARDINALITY=22, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[Country], LEVEL_NUMBER=1, MEMBER_ORDINAL=2966, MEMBER_NAME=USA, MEMBER_UNIQUE_NAME=[Customers].[USA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=USA, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Customers].[All Customers], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Customers, MEMBER_UNIQUE_NAME=[Customers].[All Customers], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Customers, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n", s); break; default: TestContext.assertEqualsVerbose( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Customers, MEMBER_UNIQUE_NAME=[Customers].[All Customers], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Customers, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[Country], LEVEL_NUMBER=1, MEMBER_ORDINAL=2966, MEMBER_NAME=USA, MEMBER_UNIQUE_NAME=[Customers].[USA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=USA, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Customers].[All Customers], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=7235, MEMBER_NAME=OR, MEMBER_UNIQUE_NAME=[Customers].[USA].[OR], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=OR, CHILDREN_CARDINALITY=11, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=8298, MEMBER_NAME=WA, MEMBER_UNIQUE_NAME=[Customers].[USA].[WA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=WA, CHILDREN_CARDINALITY=22, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n", s); break; } } public void testDatabaseMetaDataGetSets() throws SQLException { String s = checkResultSet( olapDatabaseMetaData.getSets( catalogName, null, null, null), SETS_COLUMN_NAMES); TestContext.assertEqualsVerbose( "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse, SET_NAME=[Top Sellers], SCOPE=1\n", s); s = checkResultSet( olapDatabaseMetaData.getSets( catalogName, null, null, "non existent set"), SETS_COLUMN_NAMES); TestContext.assertEqualsVerbose("", s); } // todo: More tests required for other methods on DatabaseMetaData private String checkResultSet( ResultSet resultSet, List columnNames) throws SQLException { ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); final int columnCount = resultSetMetaData.getColumnCount(); List rsColumnNames = new ArrayList(); if (columnNames != null) { for (int k = 0; k < columnCount; k++) { rsColumnNames.add( resultSetMetaData.getColumnName(k + 1)); } final HashSet set = new HashSet(columnNames); set.removeAll(rsColumnNames); assertTrue("Expected columns not found: " + set, set.isEmpty()); } assertNotNull(resultSet); int k = 0; StringBuilder buf = new StringBuilder(); while (resultSet.next()) { ++k; for (int i = 0; i < columnCount; i++) { if (i > 0) { buf.append(", "); } String s = resultSet.getString(i + 1); buf.append(resultSetMetaData.getColumnName(i + 1)) .append('=') .append(s); } buf.append(NL); } assertTrue(k >= 0); assertTrue(resultSet.isAfterLast()); return buf.toString(); } } // End MetadataTest.java olap4j-1.0.1.500/testsrc/org/olap4j/driver/0000755000175000017500000000000011421322444020040 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/driver/xmla/0000755000175000017500000000000011421322444021001 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/driver/xmla/cache/0000755000175000017500000000000011651266474022063 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/driver/xmla/cache/XmlaShaEncoderTest.java0000644000175000017500000000453411707254770026427 0ustar drazzibdrazzib/* // $Id: XmlaShaEncoderTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import junit.framework.TestCase; /** *

Test for {@link org.olap4j.driver.xmla.cache.XmlaOlap4jShaEncoder}. * * @author Luc Boudreau * @version $Id: XmlaShaEncoderTest.java 482 2012-01-05 23:27:27Z jhyde $ */ public class XmlaShaEncoderTest extends TestCase { private static final String message_1 = "This is my nifty message number 1"; private static final String message_2 = "This is my nifty message number 2"; private static final String message_1_encoded = "0821347e66167004f9aba546ae9e61ec5b471e59"; private static final String message_2_encoded = "95dfe200baddc69e2f53e78feeac445a0bdbb4e7"; public void testSimpleEncoding() throws Exception { String encoded = XmlaOlap4jShaEncoder.encodeSha1(message_1); assertEquals(message_1_encoded, encoded); } public void testDoubleEncoding() throws Exception { String encoded = XmlaOlap4jShaEncoder.encodeSha1(message_1); assertEquals(message_1_encoded, encoded); String encoded2 = XmlaOlap4jShaEncoder.encodeSha1(message_2); assertEquals(message_2_encoded, encoded2); assertFalse(encoded.equals(encoded2)); String encoded3 = XmlaOlap4jShaEncoder.encodeSha1(message_1); assertEquals(message_1_encoded, encoded3); String encoded4 = XmlaOlap4jShaEncoder.encodeSha1(message_1); assertEquals(message_1_encoded, encoded4); assertEquals(encoded3, encoded4); } } // End XmlaShaEncoderTest.java olap4j-1.0.1.500/testsrc/org/olap4j/driver/xmla/cache/XmlaDatabaseCache.java0000644000175000017500000001520411707254770026200 0ustar drazzibdrazzib/* // $Id: XmlaDatabaseCache.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import java.net.URL; import java.sql.*; import java.util.Map; /** * This mock server cache is only used to save and load * runs of the XMLA driver as a database table. * * @see Properties * @author LBoudreau * @version $Id: XmlaDatabaseCache.java 483 2012-01-05 23:43:18Z jhyde $ */ public class XmlaDatabaseCache implements XmlaOlap4jCache { private static Connection connection = null; private static final String CACHE_IDENT = "Panda steak!"; private Map props; public static enum Properties { /** * Jdbc driver class to use. Defaults to * org.hsqldb.jdbcDriver */ JDBC_DRIVER("org.hsqldb.jdbcDriver"), /** * Jdbc url to use. Defaults to * jdbc:hsqldb:file:xmla-cache/xmla-cache-hsqldb */ JDBC_URL("jdbc:hsqldb:file:xmla-cache/xmla-cache-hsqldb"), /** * Jdbc username to use. Defaults to * sa */ JDBC_USER("sa"), /** * Jdbc password to use. Defaults to * an empty string */ JDBC_PASS(""), /** * Query to execute to insert elements. Defaults to * insert into "cache" ("request", "response") values(?,?); */ QUERY_INSERT( "insert into \"cache\"(\"request\", \"response\") values(?,?);"), /** * Query to execute to select elements. Defaults to * select "request", "response" from "cache" * where "request" = ?; */ QUERY_SELECT( "select \"request\", \"response\" from \"cache\" where" + "\"request\" = ?;"), /** * Query to initialize the cache. Can be a batch of SQL. Defaults to * create table "cache" ("request" * varchar, "response" varchar); */ QUERY_INIT_CACHE( "drop table \"cache\" if exists; create table \"cache\" (\"request\" varchar, \"response\" varchar);"), /** * Should the cache insert requests/responses. * defaults to false. */ RECORD("false"), /** * Should the cache return cached responses. * defaults to false. */ PLAY("false"), /** * Should the cache execute Properties.QUERY_INIT_CACHE. * defaults to false. */ INIT("false"); private final String defaultValue; private Properties(String defaultValue) { this.defaultValue = defaultValue; } String getValueOrDefault(Map props) { if (props.containsKey(this.name())) { return props.get(name()); } else { return this.defaultValue; } } } public void flushCache() { // no op } public byte[] get(String id, URL url, byte[] request) throws XmlaOlap4jInvalidStateException { if (!Boolean.valueOf(Properties.PLAY.getValueOrDefault(props))) { return null; } try { final PreparedStatement stm = connection.prepareStatement( Properties.QUERY_SELECT.getValueOrDefault(props)); try { stm.setString(1, new String(request)); stm.execute(); ResultSet rs = stm.getResultSet(); if (rs.next()) { return rs.getString(2).getBytes(); } else { return null; } } finally { stm.close(); } } catch (Exception e) { throw new RuntimeException(e); } } public void put(String id, URL url, byte[] request, byte[] response) throws XmlaOlap4jInvalidStateException { if (!Boolean.valueOf(Properties.RECORD.getValueOrDefault(props))) { return; } try { final PreparedStatement stm = connection.prepareStatement( Properties.QUERY_INSERT.getValueOrDefault(props)); try { stm.setString(1, new String(request)); stm.setString(2, new String(response)); stm.execute(); } finally { stm.close(); } } catch (Exception e) { throw new RuntimeException(e); } } public String setParameters( Map config, Map props) { this.props = props; if (connection == null) { try { Class.forName(Properties.JDBC_DRIVER.getValueOrDefault(props)); connection = DriverManager.getConnection( Properties.JDBC_URL.getValueOrDefault(props), Properties.JDBC_USER.getValueOrDefault(props), Properties.JDBC_PASS.getValueOrDefault(props)); if (Boolean.valueOf( Properties.INIT.getValueOrDefault(props))) { final Statement stm = connection.createStatement(); try { stm.addBatch( Properties.QUERY_INIT_CACHE .getValueOrDefault(props)); stm.executeBatch(); } catch (SQLException e) { // no op } finally { stm.close(); } flushCache(); } } catch (Exception e) { throw new RuntimeException(e); } } return CACHE_IDENT; } } // End XmlaDatabaseCache.java olap4j-1.0.1.500/testsrc/org/olap4j/driver/xmla/proxy/0000755000175000017500000000000011542614630022167 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/driver/xmla/proxy/XmlaCachedProxyTest.java0000644000175000017500000003043111707254770026736 0ustar drazzibdrazzib/* // $Id: XmlaCachedProxyTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; import org.olap4j.OlapException; import org.olap4j.driver.xmla.XmlaOlap4jDriver; import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache; import junit.framework.TestCase; import java.util.HashMap; import java.util.Map; /** *

Tests both the CachedProxy implementation (HttpProxy) and the * IXmlaOlap4jCache implementation (XmlaOlap4jNamedMemoryCache). * * @author Luc Boudreau * @version $Id: XmlaCachedProxyTest.java 482 2012-01-05 23:27:27Z jhyde $ */ public class XmlaCachedProxyTest extends TestCase { final XmlaOlap4jDriver dummyDriver = new XmlaOlap4jDriver() {}; /** *

Tests if a simple and valid configuration can be used. * @throws Exception If the test fails. */ public void testCacheConfig() throws Exception { XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(dummyDriver); Map driverParameters = new HashMap(); Map cacheProperties = new HashMap(); driverParameters.put( XmlaOlap4jDriver.Property.SERVER.name(), "http://example.com"); driverParameters.put( XmlaOlap4jDriver.Property.CATALOG.name(), "CatalogName"); driverParameters.put( XmlaOlap4jDriver.Property.CACHE.name(), "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.NAME.name(), "testCacheConfig"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.MODE.name(), "LFU"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "30"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "50"); proxy.setCache(driverParameters, cacheProperties); } /** *

Makes sure that the cache mode value is validated. * @throws Exception If the test fails. */ public void testCacheModeError() throws Exception { XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(dummyDriver); Map driverParameters = new HashMap(); Map cacheProperties = new HashMap(); driverParameters.put( XmlaOlap4jDriver.Property.SERVER.name(), "http://example.com"); driverParameters.put( XmlaOlap4jDriver.Property.CATALOG.name(), "CatalogName"); driverParameters.put( XmlaOlap4jDriver.Property.CACHE.name(), "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.NAME.name(), "testCacheModeError"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.MODE.name(), "ERRONOUS VALUE MWAHAHAHAHA"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "30"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "50"); try { proxy.setCache(driverParameters, cacheProperties); } catch (OlapException e) { return; } fail("The cache mode is not validated properly"); } /** *

Makes sure that the cache timeout value is validated. * @throws Exception If the test fails. */ public void testCacheTimeoutError() throws Exception { XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(dummyDriver); Map driverParameters = new HashMap(); Map cacheProperties = new HashMap(); driverParameters.put( XmlaOlap4jDriver.Property.SERVER.name(), "http://example.com"); driverParameters.put( XmlaOlap4jDriver.Property.CATALOG.name(), "CatalogName"); driverParameters.put( XmlaOlap4jDriver.Property.CACHE.name(), "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.NAME.name(), "testCacheTimeoutError"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.MODE.name(), "LFU"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "EEE"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "50"); try { proxy.setCache(driverParameters, cacheProperties); } catch (OlapException t) { try { cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "-30"); proxy.setCache(driverParameters, cacheProperties); } catch (OlapException t2) { return; } } fail("The cache timeout is not validated properly"); } /** *

Makes sure that the cache size value is validated. * @throws Exception If the test fails. */ public void testCacheSizeError() throws Exception { XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(dummyDriver); Map driverParameters = new HashMap(); Map cacheProperties = new HashMap(); driverParameters.put( XmlaOlap4jDriver.Property.SERVER.name(), "http://example.com"); driverParameters.put( XmlaOlap4jDriver.Property.CATALOG.name(), "CatalogName"); driverParameters.put( XmlaOlap4jDriver.Property.CACHE.name(), "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.NAME.name(), "testCacheSizeError"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.MODE.name(), "LFU"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "600"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "EEE"); try { proxy.setCache(driverParameters, cacheProperties); } catch (OlapException t) { try { cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "-30"); proxy.setCache(driverParameters, cacheProperties); } catch (OlapException t2) { return; } } fail("The cache size is not validated properly"); } /** *

Makes sure that the cache class name value is validated. * @throws Exception If the test fails. */ public void testCacheNameError() throws Exception { XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(dummyDriver); Map driverParameters = new HashMap(); Map cacheProperties = new HashMap(); driverParameters.put( XmlaOlap4jDriver.Property.SERVER.name(), "http://example.com"); driverParameters.put( XmlaOlap4jDriver.Property.CATALOG.name(), "CatalogName"); driverParameters.put( XmlaOlap4jDriver.Property.CACHE.name(), "Class which doesn't exist"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.NAME.name(), "testCacheNameError"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.MODE.name(), "LFU"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "600"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "50"); try { proxy.setCache(driverParameters, cacheProperties); } catch (OlapException e) { return; } fail("The cache class name is not validated properly"); } /** *

Makes sure that a cache name is properly shared in a static * way and that the parameters are not overwritten by subsequent * connection creations. * * @throws Exception If the test fails. */ public void testCacheSharing() throws Exception { XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(dummyDriver); Map driverParameters = new HashMap(); Map cacheProperties = new HashMap(); driverParameters.put( XmlaOlap4jDriver.Property.SERVER.name(), "http://example.com"); driverParameters.put( XmlaOlap4jDriver.Property.CATALOG.name(), "CatalogName"); driverParameters.put( XmlaOlap4jDriver.Property.CACHE.name(), "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.NAME.name(), "testCacheSharing"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.MODE.name(), "LFU"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "600"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "50"); try { proxy.setCache(driverParameters, cacheProperties); } catch (Throwable e) { fail("The cache class name is not validated properly"); } driverParameters.put( XmlaOlap4jDriver.Property.SERVER.name(), "http://example2.com"); driverParameters.put( XmlaOlap4jDriver.Property.CATALOG.name(), "CatalogName2"); driverParameters.put( XmlaOlap4jDriver.Property.CACHE.name(), "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.NAME.name(), "testCacheSharing"); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.MODE.name(), "Erronous value which won't trigger an exception since a shared cache should be used."); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.TIMEOUT.name(), "Erronous value which won't trigger an exception since a shared cache should be used."); cacheProperties.put( XmlaOlap4jNamedMemoryCache.Property.SIZE.name(), "Erronous value which won't trigger an exception since a shared cache should be used."); try { // Create a new object and try with a faulty cache parameters, // but use a name which already exists in the cache directory. // This endures that 1 - the caches are shared in a static manner // and that 2 - the cache is reused and it's // parameters are not overwritten. proxy = new XmlaOlap4jHttpProxy(dummyDriver); proxy.setCache(driverParameters, cacheProperties); } catch (Throwable e) { fail( "The cache is not properly shared since an error should not " + "have been thrown."); } } } // End XmlaCachedProxyTest.java olap4j-1.0.1.500/testsrc/org/olap4j/driver/xmla/proxy/XmlaCookieManagerTest.java0000644000175000017500000000725711707254770027243 0ustar drazzibdrazzib/* // $Id: XmlaCookieManagerTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; import junit.framework.TestCase; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; /** * Unit test for cookie manager. * * @version $Id: XmlaCookieManagerTest.java 482 2012-01-05 23:27:27Z jhyde $ * @author Luc Boudreau */ public class XmlaCookieManagerTest extends TestCase { private static final String receivedCookieKey = "Set-Cookie"; public static final String sentCookieKey = "Cookie"; public static final String cookieValue = "MyTestCookie=271B79EBCBAAA37C5C51B1979441E5AC"; /** * This simple test makes sure that the cookie manager works as expected. It * creates a connection stub which returns fake Set-Cookie response * headers. The cookies are then stored in the cookie manager and a new * connection stub is created. The second connection is then passed back to * the manager and we check if the cookies were applied to the connection. * * @throws Exception */ public void testCookieManager() throws Exception { UrlConnectionStub conn = new UrlConnectionStub(new URL("http://example.com")); XmlaOlap4jCookieManager manager = new XmlaOlap4jCookieManager(); conn.connect(); manager.storeCookies(conn); conn = new UrlConnectionStub(new URL("http://example.com")); manager.setCookies(conn); assertEquals(sentCookieKey, conn.getInternalCookieKey()); assertEquals(cookieValue, conn.getInternalCookieValue()); } private static class UrlConnectionStub extends HttpURLConnection { private String internalCookieKey = null; private String internalCookieValue = null; protected UrlConnectionStub(URL u) { super(u); } @Override public void disconnect() { } @Override public boolean usingProxy() { return false; } @Override public void connect() throws IOException { this.connected = true; } @Override public String getHeaderFieldKey(int n) { if (n == 1) { return receivedCookieKey; } else { return null; } } @Override public String getHeaderField(int n) { if (n == 1) { return cookieValue; } else { return null; } } @Override public void setRequestProperty(String key, String value) { this.internalCookieKey = key; this.internalCookieValue = value; } public String getInternalCookieKey() { return internalCookieKey; } public String getInternalCookieValue() { return internalCookieValue; } } } // End XmlaCookieManagerTest.java olap4j-1.0.1.500/testsrc/org/olap4j/RemoteXmlaTester.java0000644000175000017500000000722111707254770022673 0ustar drazzibdrazzib/* // $Id: RemoteXmlaTester.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.test.TestContext; import org.olap4j.test.TestContext.Tester; import org.olap4j.test.TestContext.Wrapper; import java.sql.*; import java.util.Properties; /** * Implementation of {@link org.olap4j.test.TestContext.Tester} which speaks * to remote XML/A servers. * * @author Luc Boudreau * @version $Id: RemoteXmlaTester.java 482 2012-01-05 23:27:27Z jhyde $ */ public class RemoteXmlaTester implements Tester { public static final String DRIVER_URL_PREFIX = "jdbc:xmla:"; public static final String DRIVER_CLASS_NAME = "org.olap4j.driver.xmla.XmlaOlap4jDriver"; private String url = null; private String user = null; private String password = null; private final TestContext testContext; /** * Creates a RemoteXmlaTester. * *

The {@link org.olap4j.test.TestContext.Tester} API requires a public * constructor with a {@link org.olap4j.test.TestContext} parameter. * * @param testContext Test context */ public RemoteXmlaTester(TestContext testContext) { this.testContext = testContext; final Properties properties = testContext.getProperties(); this.url = properties.getProperty( TestContext.Property.REMOTE_XMLA_URL.path); if (url == null) { throw new RuntimeException( "Property " + TestContext.Property.REMOTE_XMLA_URL + " must be specified"); } this.user = properties.getProperty( TestContext.Property.REMOTE_XMLA_USERNAME.path); this.password = properties.getProperty( TestContext.Property.REMOTE_XMLA_PASSWORD.path); } public TestContext getTestContext() { return testContext; } public Connection createConnection() throws SQLException { return this.createConnection(url, null, null); } public Connection createConnectionWithUserPassword() throws SQLException { return this.createConnection(url, user, password); } private Connection createConnection( String url, String user, String password) { try { Class.forName(DRIVER_CLASS_NAME); return DriverManager.getConnection(url, user, password); } catch (Exception e) { throw new RuntimeException(e); } } public String getDriverClassName() { return DRIVER_CLASS_NAME; } public String getDriverUrlPrefix() { return DRIVER_URL_PREFIX; } public Flavor getFlavor() { return Flavor.REMOTE_XMLA; } public String getURL() { return this.url; } public void setUrl(String url) { this.url = url; } public Wrapper getWrapper() { return TestContext.Wrapper.NONE; } } // End RemoteXmlaTester.java olap4j-1.0.1.500/testsrc/org/olap4j/test/0000755000175000017500000000000011540707144017532 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/test/package.html0000644000175000017500000000016411421322442022004 0ustar drazzibdrazzib Contains tests for the olap4j API.

Not part of the olap4j public API.

olap4j-1.0.1.500/testsrc/org/olap4j/test/TestContext.java0000644000175000017500000006275011707521222022667 0ustar drazzibdrazzib/* // $Id: TestContext.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.test; import org.olap4j.CellSet; import org.olap4j.OlapWrapper; import org.olap4j.impl.Olap4jUtil; import org.olap4j.layout.TraditionalCellSetFormatter; import org.olap4j.mdx.*; import junit.framework.*; import org.apache.commons.dbcp.*; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; /** * Context for olap4j tests. * *

Also provides static utility methods such as {@link #fold(String)}. * *

Properties used by the test framework are described in * {@link org.olap4j.test.TestContext.Property}. * * @author jhyde * @version $Id: TestContext.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 7, 2007 */ public class TestContext { public static final String NL = System.getProperty("line.separator"); private static final String indent = " "; private static final String lineBreak2 = "\\\\n\"" + NL + indent + "+ \""; private static final String lineBreak3 = "\\n\"" + NL + indent + "+ \""; private static final Pattern LineBreakPattern = Pattern.compile("\r\n|\r|\n"); private static final Pattern TabPattern = Pattern.compile("\t"); private static Properties testProperties; private static final ThreadLocal THREAD_INSTANCE = new ThreadLocal() { protected TestContext initialValue() { return new TestContext(); } }; /** * The following classes are part of the TCK. Each driver should call them. */ public static final Class[] TCK_CLASSES = { org.olap4j.ConnectionTest.class, org.olap4j.CellSetFormatterTest.class, org.olap4j.MetadataTest.class, org.olap4j.mdx.MdxTest.class, org.olap4j.transform.TransformTest.class, org.olap4j.XmlaConnectionTest.class, org.olap4j.OlapTreeTest.class, org.olap4j.OlapTest.class, }; /** * The following tests do not depend upon the driver implementation. * They should be executed once, in olap4j's test suite, not for each * provider's test suite. */ public static final Class[] NON_TCK_CLASSES = { org.olap4j.impl.ConnectStringParserTest.class, org.olap4j.impl.Olap4jUtilTest.class, org.olap4j.impl.Base64Test.class, org.olap4j.test.ParserTest.class, org.olap4j.test.ArrayMapTest.class, org.olap4j.driver.xmla.cache.XmlaShaEncoderTest.class, org.olap4j.driver.xmla.proxy.XmlaCookieManagerTest.class, org.olap4j.driver.xmla.proxy.XmlaCachedProxyTest.class, }; private final Tester tester; private final Properties properties; /** * Intentionally private: use {@link #instance()}. */ private TestContext() { this(getStaticTestProperties()); } private TestContext(Properties properties) { assert properties != null; this.properties = properties; this.tester = createTester(this, properties); } /** * Adds all of the test classes in the TCK (Test Compatibility Kit) * to a given junit test suite. * * @param suite Suite to which to add tests */ private static void addTck(TestSuite suite) { for (Class tckClass : TCK_CLASSES) { suite.addTestSuite(tckClass); } } /** * Converts a string constant into platform-specific line endings. * * @param string String where line endings are represented as linefeed "\n" * @return String where all linefeeds have been converted to * platform-specific (CR+LF on Windows, LF on Unix/Linux) */ public static SafeString fold(String string) { if (!NL.equals("\n")) { string = Olap4jUtil.replace(string, "\n", NL); } if (string == null) { return null; } else { return new SafeString(string); } } /** * Reverses the effect of {@link #fold}; converts platform-specific line * endings in a string info linefeeds. * * @param string String where all linefeeds have been converted to * platform-specific (CR+LF on Windows, LF on Unix/Linux) * @return String where line endings are represented as linefeed "\n" */ public static String unfold(String string) { if (!NL.equals("\n")) { string = Olap4jUtil.replace(string, NL, "\n"); } if (string == null) { return null; } else { return string; } } /** * Converts an MDX parse tree to an MDX string * * @param node Parse tree * @return MDX string */ public static String toString(ParseTreeNode node) { StringWriter sw = new StringWriter(); ParseTreeWriter parseTreeWriter = new ParseTreeWriter(sw); node.unparse(parseTreeWriter); return sw.toString(); } /** * Formats a {@link org.olap4j.CellSet}. * * @param cellSet Cell set * @return String representation of cell set */ public static String toString(CellSet cellSet) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); new TraditionalCellSetFormatter().format(cellSet, pw); pw.flush(); return sw.toString(); } /** * The default instance of TestContext. * * @return default TestContext */ public static TestContext instance() { return THREAD_INSTANCE.get(); } /** * Checks that an actual string matches an expected string. If they do not, * throws a {@link junit.framework.ComparisonFailure} and prints the * difference, including the actual string as an easily pasted Java string * literal. * * @param expected Expected string * @param actual Actual string returned by test case */ public static void assertEqualsVerbose( String expected, String actual) { assertEqualsVerbose(expected, actual, true, null); } /** * Checks that an actual string matches an expected string. * *

If they do not, throws a {@link ComparisonFailure} and prints the * difference, including the actual string as an easily pasted Java string * literal. * * @param expected Expected string * @param actual Actual string * @param java Whether to generate actual string as a Java string literal * if the values are not equal * @param message Message to display, optional */ public static void assertEqualsVerbose( String expected, String actual, boolean java, String message) { assertEqualsVerbose( fold(expected), actual, java, message); } /** * Checks that an actual string matches an expected string. If they do not, * throws a {@link junit.framework.ComparisonFailure} and prints the * difference, including the actual string as an easily pasted Java string * literal. * * @param safeExpected Expected string, where all line endings have been * converted into platform-specific line endings * @param actual Actual string returned by test case * @param java Whether to print the actual value as a Java string literal * if the strings differ * @param message Message to print if the strings differ */ public static void assertEqualsVerbose( SafeString safeExpected, String actual, boolean java, String message) { String expected = safeExpected == null ? null : safeExpected.s; if ((expected == null) && (actual == null)) { return; } if ((expected != null) && expected.equals(actual)) { return; } if (message == null) { message = ""; } else { message += NL; } message += "Expected:" + NL + expected + NL + "Actual:" + NL + actual + NL; if (java) { message += "Actual java:" + NL + toJavaString(actual) + NL; } throw new ComparisonFailure(message, expected, actual); } /** * Converts a string (which may contain quotes and newlines) into a java * literal. * *

For example, *

string with "quotes" split
     * across lines
* becomes *
"string with \"quotes\" split" + NL +
     *  "across lines"
*
*/ static String toJavaString(String s) { // Convert [string with "quotes" split // across lines] // into ["string with \"quotes\" split\n" // + "across lines // s = Olap4jUtil.replace(s, "\\", "\\\\"); s = Olap4jUtil.replace(s, "\"", "\\\""); s = LineBreakPattern.matcher(s).replaceAll(lineBreak2); s = TabPattern.matcher(s).replaceAll("\\\\t"); s = "\"" + s + "\""; String spurious = NL + indent + "+ \"\""; if (s.endsWith(spurious)) { s = s.substring(0, s.length() - spurious.length()); } if (s.indexOf(lineBreak3) >= 0) { s = "fold(" + NL + indent + s + ")"; } return s; } /** * Quotes a pattern. */ public static String quotePattern(String s) { s = s.replaceAll("\\\\", "\\\\"); s = s.replaceAll("\\.", "\\\\."); s = s.replaceAll("\\+", "\\\\+"); s = s.replaceAll("\\{", "\\\\{"); s = s.replaceAll("\\}", "\\\\}"); s = s.replaceAll("\\|", "\\\\||"); s = s.replaceAll("[$]", "\\\\\\$"); s = s.replaceAll("\\?", "\\\\?"); s = s.replaceAll("\\*", "\\\\*"); s = s.replaceAll("\\(", "\\\\("); s = s.replaceAll("\\)", "\\\\)"); s = s.replaceAll("\\[", "\\\\["); s = s.replaceAll("\\]", "\\\\]"); return s; } /** * Factory method for the {@link Tester} * object which determines which driver to test. * * @param testContext Test context * @param testProperties Properties that define the properties of the tester * @return a new Tester */ private static Tester createTester( TestContext testContext, Properties testProperties) { String helperClassName = testProperties.getProperty(Property.HELPER_CLASS_NAME.path); if (helperClassName == null) { helperClassName = "org.olap4j.XmlaTester"; if (!testProperties.containsKey( TestContext.Property.XMLA_CATALOG_URL.path)) { testProperties.setProperty( TestContext.Property.XMLA_CATALOG_URL.path, "dummy_xmla_catalog_url"); } } Tester tester; try { Class clazz = Class.forName(helperClassName); final Constructor constructor = clazz.getConstructor(TestContext.class); tester = (Tester) constructor.newInstance(testContext); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } // Apply a wrapper, if the "org.olap4j.test.wrapper" property is // specified. String wrapperName = testProperties.getProperty(Property.WRAPPER.path); Wrapper wrapper; if (wrapperName == null || wrapperName.equals("")) { wrapper = Wrapper.NONE; } else { try { wrapper = Enum.valueOf(Wrapper.class, wrapperName); } catch (IllegalArgumentException e) { throw new IllegalArgumentException( "Unknown wrapper value '" + wrapperName + "'"); } } switch (wrapper) { case NONE: break; case DBCP: final BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(tester.getDriverClassName()); dataSource.setUrl(tester.getURL()); // need access to underlying connection so that we can call // olap4j-specific methods dataSource.setAccessToUnderlyingConnectionAllowed(true); tester = new DelegatingTester(tester) { public Connection createConnection() throws SQLException { return dataSource.getConnection(); } public Wrapper getWrapper() { return Wrapper.DBCP; } }; break; } return tester; } /** * Creates a test suite that executes the olap4j TCK with the given * set of properties. The properties are the same as those you can put in * {@code "test.properties"}. * * @param properties Properties * @param name Name of test suite * @return Test suite that executes the TCK */ public static TestSuite createTckSuite(Properties properties, String name) { TestContext testContext = new TestContext(properties); THREAD_INSTANCE.set(testContext); try { final TestSuite suite = new TestSuite(); suite.setName(name); addTck(suite); return suite; } finally { THREAD_INSTANCE.remove(); } } public Properties getProperties() { return properties; } /** * Enumeration of valid values for the * {@link org.olap4j.test.TestContext.Property#WRAPPER} property. */ public enum Wrapper { /** * No wrapper. */ NONE { public T unwrap( Statement statement, Class clazz) throws SQLException { return ((OlapWrapper) statement).unwrap(clazz); } public T unwrap( Connection connection, Class clazz) throws SQLException { return ((OlapWrapper) connection).unwrap(clazz); } }, /** * Instructs the olap4j testing framework to wrap connections using * the Apache commons-dbcp connection-pooling framework. */ DBCP { public T unwrap( Statement statement, Class clazz) throws SQLException { return clazz.cast( ((DelegatingStatement) statement).getInnermostDelegate()); } public T unwrap( Connection connection, Class clazz) throws SQLException { return clazz.cast( ((DelegatingConnection) connection).getInnermostDelegate()); } }; /** * Removes wrappers from a statement. * * @param statement Statement * @param clazz Desired result type * @return Unwrapped object * @throws SQLException on database error */ public abstract T unwrap( Statement statement, Class clazz) throws SQLException; /** * Removes wrappers from a connection. * * @param connection Connection * @param clazz Desired result type * @return Unwrapped object * @throws SQLException on database error */ public abstract T unwrap( Connection connection, Class clazz) throws SQLException; } /** * Returns an object containing all properties needed by the test suite. * *

Consists of system properties, overridden by the contents of * "test.properties" in the current directory, if it exists, and * in any parent or ancestor directory. This allows you to invoke the * test from any sub-directory of the source root and still pick up the * right test parameters. * * @return object containing properties needed by the test suite */ private static synchronized Properties getStaticTestProperties() { if (testProperties == null) { testProperties = new Properties(System.getProperties()); File dir = new File(System.getProperty("user.dir")); while (dir != null) { File file = new File(dir, "test.properties"); if (file.exists()) { try { testProperties.load(new FileInputStream(file)); } catch (IOException e) { // ignore } } file = new File(new File(dir, "olap4j"), "test.properties"); if (file.exists()) { try { testProperties.load(new FileInputStream(file)); } catch (IOException e) { // ignore } } dir = dir.getParentFile(); } } return testProperties; } /** * Converts a {@link Throwable} to a stack trace. */ public static String getStackTrace(Throwable e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); return sw.toString(); } /** * Shorthand way to convert array of names into segment list. * * @param names Array of names * @return Segment list */ public static List nameList(String... names) { return IdentifierNode.ofNames(names).getSegmentList(); } /** * Checks that an exception is not null and the stack trace contains a * given string. Fails otherwise. * * @param throwable Stack trace * @param pattern Seek string */ public static void checkThrowable(Throwable throwable, String pattern) { if (throwable == null) { Assert.fail("query did not yield an exception"); } String stackTrace = getStackTrace(throwable); if (stackTrace.indexOf(pattern) < 0) { Assert.fail( "error does not match pattern '" + pattern + "'; error is [" + stackTrace + "]"); } } /** * Returns this context's tester. * * @return a tester */ public Tester getTester() { return tester; } /** * Abstracts the information about specific drivers and database instances * needed by this test. This allows the same test suite to be used for * multiple implementations of olap4j. * *

Must have a public constructor that takes a * {@link org.olap4j.test.TestContext} as parameter. */ public interface Tester { /** * Returns the test context. * * @return Test context */ TestContext getTestContext(); /** * Creates a connection * * @return connection * @throws SQLException on error */ Connection createConnection() throws SQLException; /** * Returns the prefix of URLs recognized by this driver, for example * "jdbc:mondrian:" * * @return URL prefix */ String getDriverUrlPrefix(); /** * Returns the class name of the driver, for example * "mondrian.olap4j.MondrianOlap4jDriver". * * @return driver class name */ String getDriverClassName(); /** * Creates a connection using the * {@link java.sql.DriverManager#getConnection(String, String, String)} * method. * * @return connection * @throws SQLException on error */ Connection createConnectionWithUserPassword() throws SQLException; /** * Returns the URL of the FoodMart database. * * @return URL of the FoodMart database */ String getURL(); /** * Returns an enumeration indicating the driver (or strictly, the family * of drivers) supported by this Tester. Allows the test suite to * disable tests or expect slightly different results if the * capabilities of OLAP servers are different. * * @return Flavor of driver/OLAP engine we are connecting to */ Flavor getFlavor(); /** * Returns a description of the wrapper, if any, around this connection. */ Wrapper getWrapper(); enum Flavor { MONDRIAN, XMLA, REMOTE_XMLA } } /** * Implementation of {@link Tester} that delegates to an underlying tester. */ public static abstract class DelegatingTester implements Tester { protected final Tester tester; /** * Creates a DelegatingTester. * * @param tester Underlying tester to which calls are delegated */ protected DelegatingTester(Tester tester) { this.tester = tester; } public TestContext getTestContext() { return tester.getTestContext(); } public Connection createConnection() throws SQLException { return tester.createConnection(); } public String getDriverUrlPrefix() { return tester.getDriverUrlPrefix(); } public String getDriverClassName() { return tester.getDriverClassName(); } public Connection createConnectionWithUserPassword() throws SQLException { return tester.createConnectionWithUserPassword(); } public String getURL() { return tester.getURL(); } public Flavor getFlavor() { return tester.getFlavor(); } public Wrapper getWrapper() { return tester.getWrapper(); } } /** * Enumeration of system properties that mean something to the olap4j * testing framework. */ public enum Property { /** * Name of the class used by the test infrastructure to make connections * to the olap4j data source and perform other housekeeping operations. * Valid values include "mondrian.test.MondrianOlap4jTester" (the * default, per test.properties) and "org.olap4j.XmlaTester". */ HELPER_CLASS_NAME("org.olap4j.test.helperClassName"), /** * Test property that provides the value of returned by the * {@link Tester#getURL} method. */ CONNECT_URL("org.olap4j.test.connectUrl"), /** * Test property that provides the URL name of the catalog for the XMLA * driver. */ XMLA_CATALOG_URL("org.olap4j.XmlaTester.CatalogUrl"), /** * Test property related to the remote XMLA tester. * Must be a valid XMLA driver URL. */ REMOTE_XMLA_URL("org.olap4j.RemoteXmlaTester.JdbcUrl"), /** * Test property related to the remote XMLA tester. * User name to use. */ REMOTE_XMLA_USERNAME("org.olap4j.RemoteXmlaTester.Username"), /** * Test property related to the remote XMLA tester. * Password to use. */ REMOTE_XMLA_PASSWORD("org.olap4j.RemoteXmlaTester.Password"), /** * Test property that indicates the wrapper to place around the * connection. Valid values are defined by the {@link Wrapper} * enumeration, such as "Dbcp". If not specified, the connection is used * without a connection pool. */ WRAPPER("org.olap4j.test.wrapper"), ; public final String path; /** * Creates a Property enum value. * * @param path Full name of property, e.g. "org.olap4.foo.Bar". */ private Property(String path) { this.path = path; } } /** * Wrapper around a string that indicates that all line endings have been * converted to platform-specific line endings. * * @see TestContext#fold */ public static class SafeString { public final String s; /** * Creates a SafeString. * @param s String */ private SafeString(String s) { this.s = s; } } } // End TestContext.java olap4j-1.0.1.500/testsrc/org/olap4j/test/ParserTest.java0000644000175000017500000010600011707254766022502 0ustar drazzibdrazzib/* // $Id: ParserTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.test; import org.olap4j.Axis; import org.olap4j.OlapConnection; import org.olap4j.mdx.*; import org.olap4j.mdx.parser.MdxParseException; import org.olap4j.mdx.parser.MdxParser; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import java.sql.Connection; import java.sql.SQLException; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Tests the MDX parser. * * @author gjohnson, jhyde * @version $Id: ParserTest.java 482 2012-01-05 23:27:27Z jhyde $ */ public class ParserTest extends TestCase { private static final Pattern lineColPattern = Pattern.compile("At line ([0-9]+), column ([0-9]+)"); private static final Pattern lineColTwicePattern = Pattern.compile( "(?s)From line ([0-9]+), column ([0-9]+) to line ([0-9]+), column ([0-9]+): (.*)"); final TestContext testContext = TestContext.instance(); private Connection connection; public ParserTest(String name) { super(name); } protected OlapConnection getOlapConnection() throws SQLException { if (connection == null) { connection = testContext.getTester().createConnection(); } return testContext.getTester().getWrapper().unwrap( connection, OlapConnection.class); } protected void tearDown() throws Exception { if (connection != null && !connection.isClosed()) { connection.close(); connection = null; } } private MdxParser createParser() { try { OlapConnection olapConnection = getOlapConnection(); return olapConnection.getParserFactory() .createMdxParser(olapConnection); } catch (SQLException e) { throw new RuntimeException(e); } } public void testAddCarets() { assertEquals( "values (^foo^)", new ParseRegion(1, 9, 1, 11).annotate("values (foo)")); assertEquals( "abc^def", new ParseRegion(1, 4, 1, 4).annotate("abcdef")); assertEquals( "abcdef^", new ParseRegion(1, 7, 1, 7).annotate("abcdef")); assertEquals( "[1:9, 1:11]", ParseRegion.findPos("values (^foo^)").region.toString()); assertEquals( "[1:4]", ParseRegion.findPos("abc^def").region.toString()); assertEquals( "[1:7]", ParseRegion.findPos("abcdef^").region.toString()); assertNull(ParseRegion.findPos("abc").region); } public void testAxisParsing() throws Exception { checkAxisAllWays(0, "COLUMNS"); checkAxisAllWays(1, "ROWS"); checkAxisAllWays(2, "PAGES"); checkAxisAllWays(3, "CHAPTERS"); checkAxisAllWays(4, "SECTIONS"); } private void checkAxisAllWays(int axisOrdinal, String axisName) { checkAxis(axisOrdinal + "", axisName); checkAxis("AXIS(" + axisOrdinal + ")", axisName); checkAxis(axisName, axisName); } private void checkAxis( String s, String expectedName) { MdxParser p = createParser(); String q = "select [member] on " + s + " from [cube]"; SelectNode selectNode = p.parseSelect(q); List axes = selectNode.getAxisList(); assertEquals("Number of axes must be 1", 1, axes.size()); assertEquals( "Axis index name must be correct", expectedName, axes.get(0).getAxis().name()); } public void testNegativeCases() throws Exception { assertParseQueryFails( "^s^ from sales", "Syntax error at \\[1:1\\], token 's'"); assertParseQueryFails( "^seleg^ from sales", "Syntax error at \\[1:1, 1:5\\], token 'seleg'"); assertParseQueryFails( "^seleg^ from sales", "Syntax error at \\[1:1, 1:5\\], token 'seleg'"); assertParseQueryFails( "select [member] on ^axis(1.7)^ from sales", "(?s).*The axis number must be a non-negative integer, but it was 1.7."); assertParseQueryFails( "select [member] on ^foobar^ from sales", "Syntax error at \\[1:20, 1:25\\], token 'foobar'"); assertParseQueryFails( "select [member] on axis(-^ ^1) from sales", "Syntax error at \\[1:26\\], token '-'"); assertParseQueryFails( "select [member] on axis(-^1^) from sales", "Syntax error at \\[1:26\\], token '-'"); // used to be an error, but no longer assertParseQuery( "select [member] on axis(5) from sales", "SELECT\n" + "[member] ON AXIS(5)\n" + "FROM sales"); assertParseQueryFails( "select [member] on ^axes^(0) from sales", "Syntax error at \\[1:20, 1:23\\], token 'axes'"); assertParseQueryFails( "select [member] on ^0.5^ from sales", "Invalid axis specification\\. The axis number must be a non-negative integer, but it was 0\\.5\\."); assertParseQuery( "select [member] on 555 from sales", "SELECT\n" + "[member] ON AXIS(555)\n" + "FROM sales"); } public void testScannerPunc() { assertParseQuery( "with member [Measures].__Foo as 1 + 2\n" + "select __Foo on 0\n" + "from _Bar_Baz", "WITH\n" + "MEMBER [Measures].__Foo AS\n" + " (1 + 2)\n" + "SELECT\n" + "__Foo ON COLUMNS\n" + "FROM _Bar_Baz"); // # is not allowed assertParseQueryFails( "with member [Measures].#^_Foo as 1 + 2\n" + "select __Foo on 0\n" + "from _Bar#Baz", "Unexpected character '#'"); assertParseQueryFails( "with member [Measures].Foo as 1 + 2\n" + "select Foo on 0\n" + "from Bar#B^az", "Unexpected character '#'"); // The spec doesn't allow $ but SSAS allows it so we allow it too. assertParseQuery( "with member [Measures].$Foo as 1 + 2\n" + "select $Foo on 0\n" + "from Bar$Baz", "WITH\n" + "MEMBER [Measures].$Foo AS\n" + " (1 + 2)\n" + "SELECT\n" + "$Foo ON COLUMNS\n" + "FROM Bar$Baz"); // '$' is OK inside brackets too assertParseQuery( "select [measures].[$foo] on columns from sales", "SELECT\n" + "[measures].[$foo] ON COLUMNS\n" + "FROM sales"); // ']' unexpected assertParseQueryFails( "select { Customers]^.^Children } on columns from [Sales]", "Unexpected character ']'"); } public void testUnparse() { checkUnparse( "with member [Measures].[Foo] as ' 123 '\n" + "select {[Measures].members} on columns,\n" + " CrossJoin([Product].members, {[Gender].Children}) on rows\n" + "from [Sales]\n" + "where [Marital Status].[S]", "WITH\n" + "MEMBER [Measures].[Foo] AS\n" + " 123\n" + "SELECT\n" + "{[Measures].members} ON COLUMNS,\n" + "CrossJoin([Product].members, {[Gender].Children}) ON ROWS\n" + "FROM [Sales]\n" + "WHERE [Marital Status].[S]"); } private void checkUnparse(String queryString, final String expected) { try { OlapConnection olapConnection = getOlapConnection(); MdxParser mdxParser = olapConnection.getParserFactory() .createMdxParser(olapConnection); final SelectNode query = mdxParser.parseSelect(queryString); String unparsedQueryString = TestContext.toString(query); TestContext.assertEqualsVerbose(expected, unparsedQueryString); } catch (SQLException e) { throw new RuntimeException("error during parse"); } } private void assertParseQueryFails(String query, String expected) { checkFails(createParser(), query, expected); } private void assertParseExprFails(String expr, String expected) { checkFails(createParser(), wrapExpr(expr), expected); } private void checkFails(MdxParser p, String query, String expected) { final ParseRegion.RegionAndSource ras = ParseRegion.findPos(query); try { SelectNode selectNode = p.parseSelect(ras.source); fail("Must return an error, got " + selectNode); } catch (Exception e) { checkEx(e, expected, ras); } } /** * Checks whether an exception matches the pattern and expected position * expected. * * @param ex Exception thrown * @param expectedMsgPattern Expected pattern * @param ras Query and position in query */ public static void checkEx( Throwable ex, String expectedMsgPattern, ParseRegion.RegionAndSource ras) { String NL = TestContext.NL; if (null == ex) { if (expectedMsgPattern == null) { // No error expected, and no error happened. return; } else { throw new AssertionFailedError( "Expected query to throw exception, but it did not; " + "query [" + ras.source + "]; expected [" + expectedMsgPattern + "]"); } } Throwable actualException = ex; String actualMessage = actualException.getMessage(); int actualLine = -1; int actualColumn = -1; int actualEndLine = 100; int actualEndColumn = 99; // Search for a SqlParseException -- with its position set -- somewhere // in the stack. MdxParseException mpe = null; for (Throwable x = ex; x != null; x = x.getCause()) { if ((x instanceof MdxParseException) && (((MdxParseException) x).getRegion() != null)) { mpe = (MdxParseException) x; break; } if (x.getCause() == x) { break; } } if (mpe != null) { final ParseRegion region = mpe.getRegion(); actualLine = region.getStartLine(); actualColumn = region.getStartColumn(); actualEndLine = region.getEndLine(); actualEndColumn = region.getEndColumn(); actualException = mpe; actualMessage = actualException.getMessage(); } else { final String message = ex.getMessage(); if (message != null) { Matcher matcher = lineColTwicePattern.matcher(message); if (matcher.matches()) { actualLine = Integer.parseInt(matcher.group(1)); actualColumn = Integer.parseInt(matcher.group(2)); actualEndLine = Integer.parseInt(matcher.group(3)); actualEndColumn = Integer.parseInt(matcher.group(4)); actualMessage = matcher.group(5); } else { matcher = lineColPattern.matcher(message); if (matcher.matches()) { actualLine = Integer.parseInt(matcher.group(1)); actualColumn = Integer.parseInt(matcher.group(2)); } } } } if (null == expectedMsgPattern) { if (null != actualException) { actualException.printStackTrace(); fail( "Validator threw unexpected exception" + "; query [" + ras.source + "]; exception [" + actualMessage + "]; pos [line " + actualLine + " col " + actualColumn + " thru line " + actualLine + " col " + actualColumn + "]"); } } else if (null != expectedMsgPattern) { if (null == actualException) { fail( "Expected validator to throw " + "exception, but it did not; query [" + ras.source + "]; expected [" + expectedMsgPattern + "]"); } else { if ((actualColumn <= 0) || (actualLine <= 0) || (actualEndColumn <= 0) || (actualEndLine <= 0)) { throw new AssertionFailedError( "Error did not have position: " + " actual pos [line " + actualLine + " col " + actualColumn + " thru line " + actualEndLine + " col " + actualEndColumn + "]"); } String sqlWithCarets = new ParseRegion( actualLine, actualColumn, actualEndLine, actualEndColumn).annotate(ras.source); if (ras.region == null) { throw new AssertionFailedError( "todo: add carets to sql: " + sqlWithCarets); } if ((actualMessage == null) || !actualMessage.matches(expectedMsgPattern)) { actualException.printStackTrace(); final String actualJavaRegexp = (actualMessage == null) ? "null" : TestContext.toJavaString( TestContext.quotePattern(actualMessage)); fail( "Validator threw different " + "exception than expected; query [" + ras.source + "];" + NL + " expected pattern [" + expectedMsgPattern + "];" + NL + " actual [" + actualMessage + "];" + NL + " actual as java regexp [" + actualJavaRegexp + "]; pos [" + actualLine + " col " + actualColumn + " thru line " + actualEndLine + " col " + actualEndColumn + "]; sql [" + sqlWithCarets + "]"); } else if ( (ras.region != null) && ((actualLine != ras.region.getStartLine()) || (actualColumn != ras.region.getStartColumn()) || (actualEndLine != ras.region.getEndLine()) || (actualEndColumn != ras.region.getEndColumn()))) { fail( "Validator threw expected " + "exception [" + actualMessage + "]; but at pos [line " + actualLine + " col " + actualColumn + " thru line " + actualEndLine + " col " + actualEndColumn + "]; sql [" + sqlWithCarets + "]"); } } } } public void testMultipleAxes() throws Exception { MdxParser p = createParser(); String query = "select {[axis0mbr]} on axis(0), " + "{[axis1mbr]} on axis(1) from cube"; SelectNode select = p.parseSelect(query); assertNotNull(select); List axes = select.getAxisList(); assertEquals("Number of axes", 2, axes.size()); assertEquals( "Axis index name must be correct", Axis.Factory.forOrdinal(0), axes.get(0).getAxis()); assertEquals( "Axis index name must be correct", Axis.Factory.forOrdinal(1), axes.get(1).getAxis()); // now a similar query with axes reversed query = "select {[axis1mbr]} on aXiS(1), " + "{[axis0mbr]} on AxIs(0) from cube"; select = p.parseSelect(query); axes = select.getAxisList(); assertEquals("Number of axes", 2, axes.size()); assertEquals( "Axis index name must be correct", Axis.Factory.forOrdinal(0), axes.get(0).getAxis()); assertEquals( "Axis index name must be correct", Axis.Factory.forOrdinal(1), axes.get(1).getAxis()); ParseTreeNode colsSetExpr = axes.get(0).getExpression(); assertNotNull("Column tuples", colsSetExpr); CallNode fun = (CallNode)colsSetExpr; IdentifierNode identifier = (IdentifierNode) (fun.getArgList().get(0)); assertEquals(1, identifier.getSegmentList().size()); assertEquals( "Correct member on axis", "axis0mbr", identifier.getSegmentList().get(0).getName()); ParseTreeNode rowsSetExpr = axes.get(1).getExpression(); assertNotNull("Row tuples", rowsSetExpr); fun = (CallNode) rowsSetExpr; identifier = (IdentifierNode) (fun.getArgList().get(0)); assertEquals(1, identifier.getSegmentList().size()); assertEquals( "Correct member on axis", "axis1mbr", identifier.getSegmentList().get(0).getName()); } public void testCaseTest() { assertParseQuery( "with member [Measures].[Foo] as " + " ' case when x = y then \"eq\" when x < y then \"lt\" else \"gt\" end '" + "select {[foo]} on axis(0) from cube", "WITH\n" + "MEMBER [Measures].[Foo] AS\n" + " CASE WHEN (x = y) THEN \"eq\" WHEN (x < y) THEN \"lt\" ELSE \"gt\" END\n" + "SELECT\n" + "{[foo]} ON COLUMNS\n" + "FROM cube"); } public void testCaseSwitch() { assertParseQuery( "with member [Measures].[Foo] as " + " ' case x when 1 then 2 when 3 then 4 else 5 end '" + "select {[foo]} on axis(0) from cube", "WITH\n" + "MEMBER [Measures].[Foo] AS\n" + " CASE x WHEN 1 THEN 2 WHEN 3 THEN 4 ELSE 5 END\n" + "SELECT\n" + "{[foo]} ON COLUMNS\n" + "FROM cube"); } public void testDimensionProperties() { assertParseQuery( "select {[foo]} properties p1, p2 on columns from [cube]", "SELECT\n" + "{[foo]} DIMENSION PROPERTIES p1, p2 ON COLUMNS\n" + "FROM [cube]"); } public void testCellProperties() { assertParseQuery( "select {[foo]} on columns from [cube] CELL PROPERTIES FORMATTED_VALUE", "SELECT\n" + "{[foo]} ON COLUMNS\n" + "FROM [cube]\n" + "CELL PROPERTIES FORMATTED_VALUE"); } public void testIsEmpty() { assertParseExpr( "[Measures].[Unit Sales] IS EMPTY", "([Measures].[Unit Sales] IS EMPTY)"); assertParseExpr( "[Measures].[Unit Sales] IS EMPTY AND 1 IS NULL", "(([Measures].[Unit Sales] IS EMPTY) AND (1 IS NULL))"); // FIXME: "NULL" should associate as "IS NULL" rather than "NULL + 56" assertParseExpr( "- x * 5 is empty is empty is null + 56", "(((((- x) * 5) IS EMPTY) IS EMPTY) IS (NULL + 56))"); } public void testIs() { assertParseExpr( "[Measures].[Unit Sales] IS [Measures].[Unit Sales] AND [Measures].[Unit Sales] IS NULL", "(([Measures].[Unit Sales] IS [Measures].[Unit Sales]) AND ([Measures].[Unit Sales] IS NULL))"); } public void testIsNull() { assertParseExpr( "[Measures].[Unit Sales] IS NULL", "([Measures].[Unit Sales] IS NULL)"); assertParseExpr( "[Measures].[Unit Sales] IS NULL AND 1 <> 2", "(([Measures].[Unit Sales] IS NULL) AND (1 <> 2))"); assertParseExpr( "x is null or y is null and z = 5", "((x IS NULL) OR ((y IS NULL) AND (z = 5)))"); assertParseExpr( "(x is null) + 56 > 6", "(((x IS NULL) + 56) > 6)"); // FIXME: Should be: // "(((((x IS NULL) AND (a = b)) OR ((c = (d + 5))) IS NULL) + 5)" assertParseExpr( "x is null and a = b or c = d + 5 is null + 5", "(((x IS NULL) AND (a = b)) OR ((c = (d + 5)) IS (NULL + 5)))"); } public void testNull() { assertParseExpr( "Filter({[Measures].[Foo]}, Iif(1 = 2, NULL, 'X'))", "Filter({[Measures].[Foo]}, Iif((1 = 2), NULL, \"X\"))"); } public void testCast() { assertParseExpr( "Cast([Measures].[Unit Sales] AS Numeric)", "CAST([Measures].[Unit Sales] AS Numeric)"); assertParseExpr( "Cast(1 + 2 AS String)", "CAST((1 + 2) AS String)"); } public void testId() { assertParseExpr("foo", "foo"); assertParseExpr("fOo", "fOo"); assertParseExpr("[Foo].[Bar Baz]", "[Foo].[Bar Baz]"); assertParseExpr("[Foo].&[Bar]", "[Foo].&[Bar]"); } public void testIdWithKey() { // two segments each with a compound key final String mdx = "[Foo].&Key1&Key2.&[Key3]&Key4&[5]"; assertParseExpr(mdx, mdx); MdxParser p = createParser(); final String mdxQuery = wrapExpr(mdx); final SelectNode selectNode = p.parseSelect(mdxQuery); assertEquals(1, selectNode.getWithList().size()); WithMemberNode withMember = (WithMemberNode) selectNode.getWithList().get(0); final ParseTreeNode expr = withMember.getExpression(); IdentifierNode id = (IdentifierNode) expr; assertNotNull(id.getRegion()); assertEquals(3, id.getSegmentList().size()); final IdentifierSegment seg0 = id.getSegmentList().get(0); assertNotNull(seg0.getRegion()); assertEquals("Foo", seg0.getName()); assertEquals(Quoting.QUOTED, seg0.getQuoting()); final IdentifierSegment seg1 = id.getSegmentList().get(1); assertEquals(Quoting.KEY, seg1.getQuoting()); assertNull(seg1.getName()); List keyParts = seg1.getKeyParts(); assertNotNull(keyParts); assertEquals(2, keyParts.size()); assertEquals("Key1", keyParts.get(0).getName()); assertEquals( Quoting.UNQUOTED, keyParts.get(0).getQuoting()); assertEquals("Key2", keyParts.get(1).getName()); assertEquals( Quoting.UNQUOTED, keyParts.get(1).getQuoting()); final IdentifierSegment seg2 = id.getSegmentList().get(2); assertNotNull(seg2.getRegion()); assertEquals(Quoting.KEY, seg2.getQuoting()); List keyParts2 = seg2.getKeyParts(); assertNotNull(keyParts2); assertEquals(3, keyParts2.size()); assertEquals( Quoting.QUOTED, keyParts2.get(0).getQuoting()); assertEquals( Quoting.UNQUOTED, keyParts2.get(1).getQuoting()); assertEquals( Quoting.QUOTED, keyParts2.get(2).getQuoting()); assertEquals("5", keyParts2.get(2).getName()); assertNotNull(keyParts2.get(2).getRegion()); final String actual = TestContext.toString(expr); TestContext.assertEqualsVerbose(mdx, actual); } public void testIdComplex() { // simple key assertParseExpr( "[Foo].&[Key1]&[Key2].[Bar]", "[Foo].&[Key1]&[Key2].[Bar]"); // compound key assertParseExpr( "[Foo].&[1]&[Key 2]&[3].[Bar]", "[Foo].&[1]&[Key 2]&[3].[Bar]"); // compound key sans brackets assertParseExpr( "[Foo].&Key1&Key2 + 4", "([Foo].&Key1&Key2 + 4)"); // brackets are requred for numbers assertParseExprFails( "[Foo].&[1]&[Key2]&^3.[Bar]", "Syntax error at \\[1:51\\], token '&'"); // space between ampersand and key is unacceptable assertParseExprFails( "[Foo].&^ [Key2].[Bar]", "Syntax error at \\[1:40\\], token '&'"); // underscore after ampersand is unacceptable assertParseExprFails( "[Foo].&^_Key2.[Bar]", "Syntax error at \\[1:40\\], token '&'"); // but underscore is OK within brackets assertParseExpr( "[Foo].&[_Key2].[Bar]", "[Foo].&[_Key2].[Bar]"); } // todo: enable this public void _testCloneQuery() throws SQLException { OlapConnection olapConnection = getOlapConnection(); MdxParser mdxParser = olapConnection.getParserFactory() .createMdxParser(olapConnection); final SelectNode query = mdxParser.parseSelect( "select {[Measures].Members} on columns,\n" + " {[Store].Members} on rows\n" + "from [Sales]\n" + "where ([Gender].[M])"); SelectNode selectClone = null; // select.copy(); assertTrue(selectClone instanceof SelectNode); assertEquals( TestContext.toString(selectClone), TestContext.toString(query)); } /** * Tests parsing of numbers. */ public void testNumbers() { // Number: [+-] [ . ] [e [+-] ] assertParseExpr("2", "2"); // leading '-' is treated as an operator -- that's ok assertParseExpr("-3", "(- 3)"); // leading '+' is ignored -- that's ok assertParseExpr("+45", "45"); // space bad assertParseExprFails( "4 ^5^", "Syntax error at \\[1:35\\], token '5\\'"); assertParseExpr("3.14", "3.14"); assertParseExpr(".12345", "0.12345"); // lots of digits left and right of point assertParseExpr("31415926535.89793", "31415926535.89793"); assertParseExpr( "31415926535897.9314159265358979", "31415926535897.9314159265358979"); assertParseExpr("3.141592653589793", "3.141592653589793"); assertParseExpr( "-3141592653589793.14159265358979", "(- 3141592653589793.14159265358979)"); // exponents akimbo assertParseExpr("1e2", "100"); assertParseExprFails( "1e2e^3^", // todo: fix parser; should be "1e2^e3^" "Syntax error at .* token 'e3'"); assertParseExpr("1.2e3", "1200"); assertParseExpr("-1.2345e3", "(- 1234.5)"); assertParseExprFails( "1.2e3.^4^", // todo: fix parser; should be "1.2e3^.4^" "Syntax error at .* token '0.4'"); assertParseExpr(".00234e0003", "2.34"); assertParseExpr(".00234e-0067", "2.34E-70"); } /** * Testcase for bug 1688645, "High precision number in MDX causes overflow". * The problem was that "5000001234" exceeded the precision of the int being * used to gather the mantissa. */ public void testLargePrecision() { // Now, a query with several numeric literals. This is the original // testcase for the bug. assertParseQuery( "with member [Measures].[Small Number] as '[Measures].[Store Sales] / 9000'\n" + "select\n" + "{[Measures].[Small Number]} on columns,\n" + "{Filter([Product].[Product Department].members, [Measures].[Small Number] >= 0.3\n" + "and [Measures].[Small Number] <= 0.5000001234)} on rows\n" + "from Sales\n" + "where ([Time].[1997].[Q2].[4])", "WITH\n" + "MEMBER [Measures].[Small Number] AS\n" + " ([Measures].[Store Sales] / 9000)\n" + "SELECT\n" + "{[Measures].[Small Number]} ON COLUMNS,\n" + "{Filter([Product].[Product Department].members, (([Measures].[Small Number] >= 0.3) AND ([Measures].[Small Number] <= 0.5000001234)))} ON ROWS\n" + "FROM Sales\n" + "WHERE ([Time].[1997].[Q2].[4])"); } public void testIdentifier() { // must have at least one segment IdentifierNode id; try { id = new IdentifierNode(); fail("expected exception"); } catch (IllegalArgumentException e) { // ok } id = new IdentifierNode( new NameSegment("foo")); assertEquals("[foo]", id.toString()); // append does not mutate IdentifierNode id2 = id.append( new KeySegment( new NameSegment( null, "bar", Quoting.QUOTED))); assertTrue(id != id2); assertEquals("[foo]", id.toString()); assertEquals("[foo].&[bar]", id2.toString()); // cannot mutate segment list final List segments = id.getSegmentList(); try { segments.remove(0); fail("expected exception"); } catch (UnsupportedOperationException e) { // ok } try { segments.clear(); fail("expected exception"); } catch (UnsupportedOperationException e) { // ok } try { segments.add( new NameSegment("baz")); fail("expected exception"); } catch (UnsupportedOperationException e) { // ok } } /** * Test case for empty expressions. Test case for bug 3030772, "DrilldownLevelTop parser error". */ public void testEmptyExpr() { assertParseQuery( "select NON EMPTY HIERARCHIZE(\n" + " {DrillDownLevelTop(\n" + " {[Product].[All Products]},3,,[Measures].[Unit Sales])}" + " ) ON COLUMNS\n" + "from [Sales]\n", "SELECT\n" + "NON EMPTY HIERARCHIZE({DrillDownLevelTop({[Product].[All Products]}, 3, , [Measures].[Unit Sales])}) ON COLUMNS\n" + "FROM [Sales]"); // more advanced; the actual test case in the bug assertParseQuery( "SELECT {[Measures].[NetSales]}" + " DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON COLUMNS ," + " NON EMPTY HIERARCHIZE(AddCalculatedMembers(" + "{DrillDownLevelTop({[ProductDim].[Name].[All]}, 10, ," + " [Measures].[NetSales])}))" + " DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON ROWS " + "FROM [cube]", "SELECT\n" + "{[Measures].[NetSales]} DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON COLUMNS,\n" + "NON EMPTY HIERARCHIZE(AddCalculatedMembers({DrillDownLevelTop({[ProductDim].[Name].[All]}, 10, , [Measures].[NetSales])})) DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON ROWS\n" + "FROM [cube]"); } /** * Test case for SELECT in the FROM clause. */ public void testInnerSelect() { assertParseQuery( "SELECT FROM " + "(SELECT ({[ProductDim].[Product Group].&[Mobile Phones]}) " + "ON COLUMNS FROM [cube]) CELL PROPERTIES VALUE", "SELECT\n" + "FROM (\n" + " SELECT\n" + " {[ProductDim].[Product Group].&[Mobile Phones]} ON COLUMNS\n" + " FROM [cube])\n" + "CELL PROPERTIES VALUE"); } /** * Test case for adding to WITH clause. */ public void testWithAdd() { SelectNode selectNode = new SelectNode(); IdentifierNode startDate = new IdentifierNode( new NameSegment("Date"), new NameSegment("2010-01-03")); IdentifierNode endDate = new IdentifierNode( new NameSegment("Date"), new NameSegment("2010-10-03")); IdentifierNode name = new IdentifierNode( new NameSegment("Date"), new NameSegment("Date Range")); CallNode cn = new CallNode(null, ":", Syntax.Infix, startDate, endDate); ParseTreeNode exp = new CallNode( null, "Aggregate", Syntax.Function, new CallNode( null, "{}", Syntax.Braces, cn)); WithMemberNode withMemberNode = new WithMemberNode( null, name, exp, Collections.emptyList()); selectNode.setFrom( IdentifierNode.parseIdentifier("Sales")); selectNode.getWithList().add(withMemberNode); final String queryString = selectNode.toString(); TestContext.assertEqualsVerbose( "WITH\n" + "MEMBER [Date].[Date Range] AS\n" + " Aggregate({([Date].[2010-01-03] : [Date].[2010-10-03])})\n" + "SELECT\n" + "FROM Sales", queryString); // check that unparsed string is valid assertParseQuery(queryString, TestContext.unfold(queryString)); } /** * Parses an MDX query and asserts that the result is as expected when * unparsed. * * @param mdx MDX query * @param expected Expected result of unparsing */ private void assertParseQuery(String mdx, final String expected) { MdxParser p = createParser(); final SelectNode selectNode = p.parseSelect(mdx); final String actual = TestContext.toString(selectNode); TestContext.assertEqualsVerbose(expected, actual); } /** * Parses an MDX expression and asserts that the result is as expected when * unparsed. * * @param expr MDX query * @param expected Expected result of unparsing */ private void assertParseExpr(String expr, final String expected) { MdxParser p = createParser(); final String mdx = wrapExpr(expr); final SelectNode selectNode = p.parseSelect(mdx); assertEquals(1, selectNode.getWithList().size()); WithMemberNode withMember = (WithMemberNode) selectNode.getWithList().get(0); final String actual = TestContext.toString(withMember.getExpression()); TestContext.assertEqualsVerbose(expected, actual); } private String wrapExpr(String expr) { return "with member [Measures].[Foo] as " + expr + "\n select from [Sales]"; } } // End ParserTest.java olap4j-1.0.1.500/testsrc/org/olap4j/test/ArrayMapTest.java0000644000175000017500000003103011707254766022762 0ustar drazzibdrazzib/* // $Id: ArrayMapTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.test; import org.olap4j.impl.ArrayMap; import org.olap4j.impl.UnmodifiableArrayMap; import junit.framework.TestCase; import java.util.*; /** * Unit test for {@link org.olap4j.impl.ArrayMap}. * * @author jhyde * @version $Id: ArrayMapTest.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 9, 2007 */ public class ArrayMapTest extends TestCase { public void testArrayMap() { final ArrayMap map = new ArrayMap(); // clear empty map map.clear(); assertEquals(0, map.size()); assertTrue(map.isEmpty()); map.put("Paul", 4); assertEquals(1, map.size()); assertFalse(map.isEmpty()); assertTrue(map.containsKey("Paul")); assertFalse(map.containsKey("Keith")); Integer value = map.put("Paul", 5); assertEquals(1, map.size()); assertEquals(4, value.intValue()); assertEquals(5, map.get("Paul").intValue()); // null values are allowed map.put("Paul", null); assertNull(map.get("Paul")); assertTrue(map.containsKey("Paul")); // null keys are allowed map.put(null, -99); assertEquals(-99, map.get(null).intValue()); assertTrue(map.containsKey(null)); assertEquals(-99, map.remove(null).intValue()); final Map beatles = new ArrayMap(); beatles.put("John", 4); beatles.put("Paul", 4); beatles.put("George", 6); beatles.put("Ringo", 5); map.putAll(beatles); assertEquals(4, map.size()); assertEquals( new HashSet( Arrays.asList("John", "Paul", "George", "Ringo")), map.keySet()); assertEquals(Arrays.asList(4, 4, 6, 5), map.values()); String keys = ""; int valueTotal = 0; for (Map.Entry entry : map.entrySet()) { valueTotal += entry.getValue(); keys += entry.getKey(); } assertEquals(19, valueTotal); assertEquals("PaulJohnGeorgeRingo", keys); value = map.remove("Mick"); assertNull(value); assertEquals(4, map.size()); // corner case: remove last value value = map.remove("Ringo"); assertEquals(5, value.intValue()); assertEquals(3, map.size()); // corner case: remove first value value = map.remove("Paul"); assertEquals(4, value.intValue()); assertEquals(2, map.size()); // add key back in and it becomes last value map.put("Paul", 27); assertEquals(Arrays.asList(4, 6, 27), map.values()); // remove an interior value map.remove("George"); assertEquals(2, map.size()); } /** * Oops, forgot that I had written the first test and wrote another. Mostly * overlap with {@link #testArrayMap()}, but can't hurt. */ public void testArrayMap2() { final ArrayMap map = new ArrayMap(); final HashMap hashMap = new HashMap(); assertEquals(0, map.size()); assertEquals(map, hashMap); assertEquals(map.hashCode(), hashMap.hashCode()); // put map.put("foo", 0); assertEquals(1, map.size()); assertEquals(1, map.keySet().size()); assertEquals(1, map.values().size()); // equivalence to hashmap hashMap.put("foo", 0); assertEquals(map, hashMap); assertEquals(hashMap, map); assertEquals(map.hashCode(), hashMap.hashCode()); // containsKey, get assertTrue(map.containsKey("foo")); assertFalse(map.containsKey("bar")); assertEquals(Integer.valueOf(0), map.get("foo")); assertNull(map.get("baz")); // putall final Map hashMap2 = new HashMap(); hashMap2.put("bar", 1); hashMap2.put("foo", 2); hashMap2.put("baz", 0); map.putAll(hashMap2); hashMap.putAll(hashMap2); assertEquals(3, map.size()); assertEquals(map, hashMap); assertEquals(hashMap, map); assertEquals(map.hashCode(), hashMap.hashCode()); assertEquals(map.keySet(), hashMap.keySet()); // values collections have same contents, not necessarily in same order assertEquals( new HashSet(map.values()), new HashSet(hashMap.values())); // replace existing key map.put("foo", -5); hashMap.put("foo", -5); assertEquals(3, map.size()); assertEquals(Integer.valueOf(-5), map.get("foo")); assertEquals(map, hashMap); assertEquals(hashMap, map); // null key assertFalse(map.containsKey(null)); map.put(null, 75); assertEquals(Integer.valueOf(75), map.get(null)); assertTrue(map.containsKey(null)); // null value map.put("zzzz", null); assertTrue(map.containsKey("zzzz")); assertNull(map.get("zzzz")); // compare to hashmap hashMap.put(null, 75); hashMap.put("zzzz", null); assertEquals(map, hashMap); assertEquals(hashMap, map); // isEmpty, clear assertFalse(map.isEmpty()); map.clear(); assertTrue(map.isEmpty()); assertEquals(0, map.size()); // putAll to populate empty map (uses different code path than putAll // on non-empty map) final Map map2 = new ArrayMap(); map2.putAll(hashMap); assertEquals(map2, hashMap); // copy constructor final Map map3 = new ArrayMap(hashMap); assertEquals(map3, hashMap); // of final Map map4 = ArrayMap.of( "foo", -5, "bar", 1, "baz", 0, null, 75, "zzzz", null); assertEquals(map4, hashMap); // toString assertEquals( "{foo=-5, bar=1, baz=0, null=75, zzzz=null}", map4.toString()); assertEquals("{}", new ArrayMap().toString()); } /** * Test for {@link org.olap4j.impl.UnmodifiableArrayMap}. */ public void testUnmodifiableArrayMap() { Map map; final Map hashMap = new HashMap(); map = new UnmodifiableArrayMap(hashMap); assertEquals(0, map.size()); assertEquals(map, hashMap); assertEquals(map.hashCode(), hashMap.hashCode()); // put try { int x = map.put("foo", 0); fail("expected fail, got " + x); } catch (UnsupportedOperationException e) { // ok } hashMap.put("foo", 0); map = new UnmodifiableArrayMap(hashMap); assertEquals(1, map.size()); assertEquals(1, map.keySet().size()); assertEquals(1, map.values().size()); // equivalence to hashmap assertEquals(map, hashMap); assertEquals(hashMap, map); assertEquals(map.hashCode(), hashMap.hashCode()); // containsKey, get assertTrue(map.containsKey("foo")); assertFalse(map.containsKey("bar")); assertEquals(Integer.valueOf(0), map.get("foo")); assertNull(map.get("baz")); // putall final Map hashMap2 = new HashMap(); hashMap2.put("bar", 1); hashMap2.put("foo", 2); hashMap2.put("baz", 0); try { map.putAll(hashMap2); fail("expected fail"); } catch (UnsupportedOperationException e) { // ok } hashMap.putAll(hashMap2); map = new UnmodifiableArrayMap(hashMap); assertEquals(3, map.size()); assertEquals(map, hashMap); assertEquals(hashMap, map); assertEquals(map.hashCode(), hashMap.hashCode()); assertEquals(map.keySet(), hashMap.keySet()); // values collections have same contents, not necessarily in same order assertEquals( new HashSet(map.values()), new HashSet(hashMap.values())); // replace existing key try { int x = map.put("foo", -5); fail("expected fail, got " + x); } catch (UnsupportedOperationException e) { // ok } hashMap.put("foo", -5); map = new UnmodifiableArrayMap(hashMap); assertEquals(3, map.size()); assertEquals(Integer.valueOf(-5), map.get("foo")); assertEquals(map, hashMap); assertEquals(hashMap, map); // null key assertFalse(map.containsKey(null)); hashMap.put(null, 75); map = new UnmodifiableArrayMap(hashMap); assertEquals(Integer.valueOf(75), map.get(null)); assertTrue(map.containsKey(null)); // null value hashMap.put("zzzz", null); map = new UnmodifiableArrayMap(hashMap); assertTrue(map.containsKey("zzzz")); assertNull(map.get("zzzz")); // compare to hashmap assertEquals(map, hashMap); assertEquals(hashMap, map); // isEmpty, clear assertFalse(map.isEmpty()); try { map.clear(); fail("expected fail"); } catch (UnsupportedOperationException e) { // ok } assertTrue( new UnmodifiableArrayMap( Collections.emptyMap()).isEmpty()); // copy constructor final Map map3 = new UnmodifiableArrayMap(hashMap); assertEquals(map3, hashMap); // of final Map map4 = UnmodifiableArrayMap.of( "foo", -5, "bar", 1, "baz", 0, null, 75, "zzzz", null); assertEquals(map4, hashMap); // order is preserved final List keyList = Arrays.asList( "foo", "bar", "baz", null, "zzzz"); assertEquals( new ArrayList(map4.keySet()), keyList); final List valueList = Arrays.asList(-5, 1, 0, 75, null); assertEquals( new ArrayList(map4.values()), valueList); final Iterator valueIter = valueList.iterator(); final Iterator keyIter = keyList.iterator(); for (Map.Entry entry : map4.entrySet()) { assertEquals(entry.getKey(), keyIter.next()); assertEquals(entry.getValue(), valueIter.next()); } assertFalse(keyIter.hasNext()); assertFalse(valueIter.hasNext()); // of(Map) - zero entries hashMap.clear(); final Map map5 = UnmodifiableArrayMap.of(hashMap); assertTrue(map5 == Collections.emptyMap()); // of(Map) - one entry hashMap.put("foo", -5); final Map map6 = UnmodifiableArrayMap.of(hashMap); assertTrue( map6.getClass() == Collections.singletonMap("7", "y").getClass()); // of(Map) - 2 or more entries hashMap.put("bar", 1); hashMap.put("baz", 0); final Map map7 = UnmodifiableArrayMap.of(hashMap); assertEquals(map7, hashMap); // toString assertEquals( "{foo=-5, bar=1, baz=0, null=75, zzzz=null}", map4.toString()); assertEquals("{}", map5.toString()); } } // End ArrayMapTest.java olap4j-1.0.1.500/testsrc/org/olap4j/OlapTreeTest.java0000644000175000017500000000554311707254770022007 0ustar drazzibdrazzib/* // $Id: OlapTreeTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.metadata.*; import org.olap4j.test.TestContext; import junit.framework.TestCase; import java.sql.Connection; import java.util.HashMap; import java.util.Map; /** * Tests some particularities of the OLAP tree objects. * @author Luc Boudreau */ public class OlapTreeTest extends TestCase { private final TestContext.Tester tester = TestContext.instance().getTester(); /** * Simple strategy to prevent connection leaks: each test that needs a * connection assigns it to this field, and {@link #tearDown()} closes it * if it is not already closed. */ private Connection connection; protected void tearDown() throws Exception { // Simple strategy to prevent connection leaks if (connection != null && !connection.isClosed()) { connection.close(); connection = null; } } /** * Tests if olap objects can be included in collections and * retrieved properly. */ public void testHashCompatibility() throws Exception { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Schema schema = olapConnection.getOlapSchema(); Cube cube = schema.getCubes().get("Sales"); Map dimensionMap = new HashMap(); Dimension dim1 = cube.getDimensions().get("Promotion Media"); dimensionMap.put(dim1, "Test1"); assertTrue(dimensionMap.containsKey(dim1)); assertEquals("Test1", dimensionMap.get(dim1)); Map hierarchyMap = new HashMap(); Hierarchy hchy1 = dim1.getDefaultHierarchy(); hierarchyMap.put(hchy1, "Test2"); assertTrue(hierarchyMap.containsKey(hchy1)); assertEquals("Test2", hierarchyMap.get(hchy1)); assertTrue(dimensionMap.containsKey(hchy1.getDimension())); } } // End OlapTreeTest.java olap4j-1.0.1.500/testsrc/org/olap4j/mdx/0000755000175000017500000000000011430532676017347 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/mdx/MdxTest.java0000644000175000017500000001657411707254770021622 0ustar drazzibdrazzib/* // $Id: MdxTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.mdx.parser.MdxParser; import org.olap4j.mdx.parser.impl.DefaultMdxParserImpl; import org.olap4j.test.TestContext; import junit.framework.TestCase; import java.util.*; /** * Testcase for org.olap4j.mdx package. * * @author jhyde * @version $Id: MdxTest.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 12, 2007 */ public class MdxTest extends TestCase { /** * Tests methods {@link IdentifierNode#quoteMdxIdentifier(String)}, * {@link IdentifierNode#unparseIdentifierList(java.util.List)}. */ public void testQuoteMdxIdentifier() { assertEquals( "[San Francisco]", IdentifierNode.quoteMdxIdentifier("San Francisco")); assertEquals( "[a [bracketed]] string]", IdentifierNode.quoteMdxIdentifier("a [bracketed] string")); assertEquals( "[Store].[USA].[California]", IdentifierNode.unparseIdentifierList( Arrays.asList( new NameSegment( null, "Store", Quoting.QUOTED), new NameSegment( null, "USA", Quoting.QUOTED), new NameSegment( null, "California", Quoting.QUOTED)))); } public void testImplode() { List fooBar = Arrays.asList( new NameSegment( null, "foo", Quoting.UNQUOTED), new NameSegment( null, "bar", Quoting.QUOTED)); assertEquals( "foo.[bar]", IdentifierNode.unparseIdentifierList(fooBar)); List empty = Collections.emptyList(); assertEquals("", IdentifierNode.unparseIdentifierList(empty)); List nasty = Arrays.asList( new NameSegment( null, "string", Quoting.QUOTED), new NameSegment( null, "with", Quoting.QUOTED), new NameSegment( null, "a [bracket] in it", Quoting.QUOTED)); assertEquals( "[string].[with].[a [bracket]] in it]", IdentifierNode.unparseIdentifierList(nasty)); } public void testParseIdentifier() { List segments = IdentifierNode.parseIdentifier( "[string].[with].[a [bracket]] in it]").getSegmentList(); assertEquals(3, segments.size()); assertEquals( "a [bracket] in it", segments.get(2).getName()); assertEquals( Quoting.QUOTED, segments.get(2).getQuoting()); segments = IdentifierNode.parseIdentifier( "[Worklog].[All].[calendar-[LANGUAGE]].js]").getSegmentList(); assertEquals(3, segments.size()); assertEquals( "calendar-[LANGUAGE].js", segments.get(2).getName()); segments = IdentifierNode.parseIdentifier("[foo].bar").getSegmentList(); assertEquals(2, segments.size()); assertEquals( Quoting.QUOTED, segments.get(0).getQuoting()); assertEquals( Quoting.UNQUOTED, segments.get(1).getQuoting()); try { segments = IdentifierNode.parseIdentifier("[foo].[bar").getSegmentList(); fail("expected exception, got " + segments); } catch (RuntimeException e) { assertEquals( "Expected ']', in member identifier '[foo].[bar'", e.getMessage()); } } /** * Unit test for {@link org.olap4j.mdx.IdentifierNode#ofNames(String...)}. */ public void testIdentifierOfNames() { IdentifierNode identifierNode = IdentifierNode.ofNames( "string", "with", "a [bracket] in it"); List segments = identifierNode.getSegmentList(); assertEquals(3, segments.size()); assertEquals( "a [bracket] in it", segments.get(2).getName()); assertEquals( Quoting.QUOTED, segments.get(2).getQuoting()); assertEquals( "[string].[with].[a [bracket]] in it]", identifierNode.toString()); // Empty array is invalid. try { identifierNode = IdentifierNode.ofNames(); fail("expected error, got " + identifierNode); } catch (IllegalArgumentException e) { // ok } // Array containing null is not valid. try { identifierNode = IdentifierNode.ofNames("foo", null, "bar"); fail("expected error, got " + identifierNode); } catch (NullPointerException e) { // ok } } /** * Tests that escaped single quotes ('') nested inside a quoted * part of a query are handled correctly. The MDX language allows * expressions for calculated members and sets to be specified with and * without single quotes; the unparser generates expressions without quotes. */ public void testQuoteEscaping() { String query = "WITH\n" + "MEMBER [CustomerDim].[CustomerName].[XL_QZX] AS 'Aggregate" + "({[CustomerDim].[CustomerName].&[ABC INT''L]," + " [CustomerDim].[CustomerName].&[XYZ]})'\n" + "SELECT\n" + "{[Measures].[Sales]} ON COLUMNS\n" + "FROM [cube]\n" + "WHERE ([CustomerDim].[CustomerName].[XL_QZX])"; final MdxParser parser = new DefaultMdxParserImpl(); SelectNode rootNode = parser.parseSelect(query); TestContext.assertEqualsVerbose( "WITH\n" + "MEMBER [CustomerDim].[CustomerName].[XL_QZX] AS\n" + " Aggregate({[CustomerDim].[CustomerName].&[ABC INT'L], [CustomerDim].[CustomerName].&[XYZ]})\n" + "SELECT\n" + "{[Measures].[Sales]} ON COLUMNS\n" + "FROM [cube]\n" + "WHERE ([CustomerDim].[CustomerName].[XL_QZX])", rootNode.toString()); // Now named set query = "WITH SET Foo as Filter(Bar.Members, Instr(Name, \"'\") > 0)\n" + "SELECT FROM [Cube]"; rootNode = parser.parseSelect(query); TestContext.assertEqualsVerbose( "WITH\n" + "SET Foo AS\n" + " Filter(Bar.Members, (Instr(Name, \"'\") > 0))\n" + "SELECT\n" + "FROM [Cube]", rootNode.toString()); } } // End MdxTest.java olap4j-1.0.1.500/testsrc/org/olap4j/OlapTest.java0000644000175000017500000017701711711470530021162 0ustar drazzibdrazzib/* // $Id: OlapTest.java 498 2012-01-30 16:30:42Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.impl.Bug; import org.olap4j.mdx.SelectNode; import org.olap4j.metadata.*; import org.olap4j.query.*; import org.olap4j.query.QueryDimension.HierarchizeMode; import org.olap4j.query.Selection.Operator; import org.olap4j.test.TestContext; import junit.framework.TestCase; import java.sql.Connection; import java.sql.DriverManager; import static org.olap4j.test.TestContext.nameList; /** * Unit test illustrating sequence of calls to olap4j API from a graphical * client. * * @since May 22, 2007 * @author James Dixon * @version $Id: OlapTest.java 498 2012-01-30 16:30:42Z lucboudreau $ */ public class OlapTest extends TestCase { private TestContext testContext = TestContext.instance(); private TestContext.Tester tester = testContext.getTester(); private Connection connection; public OlapTest() { super(); } protected void tearDown() throws Exception { // Simple strategy to prevent connection leaks if (connection != null && !connection.isClosed()) { connection.close(); connection = null; } testContext = null; tester = null; } public Cube getFoodmartCube(String cubeName) throws Exception { connection = tester.createConnection(); OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); Catalog catalog = olapConnection.getOlapCatalogs().get("FoodMart"); NamedList schemas = catalog.getSchemas(); if (schemas.size() == 0) { return null; } // Use the first schema Schema schema = schemas.get(0); // Get a list of cube objects and dump their names NamedList cubes = schema.getCubes(); if (cubes.size() == 0) { // no cubes where present return null; } // take the first cube return cubes.get(cubeName); } public void testModel() throws Exception { if (false) { // define the connection information String schemaUri = "file:/open/mondrian/demo/FoodMart.xml"; String schemaName = "FoodMart"; String userName = "foodmartuser"; String password = "foodmartpassword"; String jdbc = "jdbc:mysql://localhost/foodmart?user=foodmartuser" + "&password=foodmartpassword"; // Create a connection object to the specific implementation of an // olap4j source. This is the only provider-specific code. Class.forName("mondrian.olap4j.MondrianOlap4jDriver"); connection = DriverManager.getConnection( "jdbc:mondrian:Jdbc=" + jdbc + ";User=" + userName + ";Password=" + password + ";Catalog=" + schemaUri); } else { connection = tester.createConnection(); } OlapConnection olapConnection = tester.getWrapper().unwrap(connection, OlapConnection.class); // REVIEW: jhyde: Why do you want to name connections? We could add // a connect string property 'description', if that helps // connection.setName("First Connection"); // The code from here on is generic olap4j stuff // Get a list of the schemas available from this connection and dump // their names. Catalog catalog = olapConnection.getOlapCatalogs().get("FoodMart"); NamedList schemas = catalog.getSchemas(); if (schemas.size() == 0) { // No schemas were present return; } // Use the first schema Schema schema = schemas.get(0); // Get a list of cube objects and dump their names NamedList cubes = schema.getCubes(); if (cubes.size() == 0) { // no cubes where present return; } // take the "Sales" cube Cube cube = cubes.get("Sales"); // The code from this point on is for the Foodmart schema // Create a new query Query query = new Query("my query", cube); QueryDimension productQuery = query.getDimension("Product"); QueryDimension storeQuery = query.getDimension("Store"); QueryDimension timeQuery = query.getDimension("Time"); Member productMember = cube.lookupMember(nameList("Product", "Drink")); // create some selections for Store storeQuery.include( Selection.Operator.CHILDREN, nameList("Store", "USA")); // create some selections for Product productQuery.clearInclusions(); productQuery.include( Selection.Operator.CHILDREN, productMember); productQuery.include( Selection.Operator.CHILDREN, nameList("Product", "Food")); // create some selections for Time timeQuery.include( Selection.Operator.CHILDREN, nameList("Time", "1997")); // place our dimensions on the axes query.getAxis(Axis.COLUMNS).addDimension(productQuery); assert productQuery.getAxis() == query.getAxis(Axis.COLUMNS); query.getAxis(Axis.ROWS).addDimension(storeQuery); query.getAxis(Axis.ROWS).addDimension(timeQuery); try { query.getAxis(Axis.ROWS).addDimension(storeQuery); fail("expected exception"); } catch (Exception e) { assertTrue( e.getMessage().contains("dimension already on this axis")); } query.validate(); query.execute(); // for shits and giggles we'll swap the axes over query.swapAxes(); query.validate(); query.execute(); } public void testSelectionModes() throws Exception { 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"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{[Product].[Drink].Children} ON ROWS\n" + "FROM [Sales]", mdxString); // TEST ANCESTORS SELECTION productDimension.clearInclusions(); productDimension.include( Selection.Operator.ANCESTORS, nameList("Product", "Drink")); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{Ascendants([Product].[Drink])} ON ROWS\n" + "FROM [Sales]", mdxString); // TEST DESCENDANTS SELECTION productDimension.clearInclusions(); productDimension.include( Selection.Operator.DESCENDANTS, nameList("Product", "Drink")); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{Descendants([Product].[Drink])} ON ROWS\n" + "FROM [Sales]", mdxString); // TEST INCLUDE_CHILDREN SELECTION productDimension.clearInclusions(); productDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Product", "Drink")); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{{[Product].[Drink], [Product].[Drink].Children}} ON ROWS\n" + "FROM [Sales]", mdxString); // TEST SIBLINGS SELECTION productDimension.clearInclusions(); productDimension.include( Selection.Operator.SIBLINGS, nameList("Product", "Drink")); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{[Product].[Drink].Siblings} ON ROWS\n" + "FROM [Sales]", mdxString); // TEST LEVEL MEMBERS SELECTION NamedList productLevels = productDimension.getDimension().getDefaultHierarchy().getLevels(); Level productDepartments = productLevels.get("Product Department"); productDimension.include(productDepartments); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{[Product].[Drink].Siblings, [Product].[Product Department].Members} ON ROWS\n" + "FROM [Sales]", mdxString); } public void testMultipleDimensionSelections() throws Exception { 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"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include( Selection.Operator.CHILDREN, nameList("Time", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "CrossJoin([Product].[Drink].Children, " + "CrossJoin({[Store].[USA], " + "[Store].[USA].Children}, " + "[Time].[1997].Children)) ON ROWS\n" + "FROM [Sales]", mdxString); } public void testSwapAxes() throws Exception { 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"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); assertEquals( Axis.ROWS, productDimension.getAxis().getLocation()); assertEquals( Axis.COLUMNS, measuresDimension.getAxis().getLocation()); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{[Product].[Drink].Children} ON ROWS\n" + "FROM [Sales]", mdxString); query.swapAxes(); assertEquals( Axis.COLUMNS, productDimension.getAxis().getLocation()); assertEquals( Axis.ROWS, measuresDimension.getAxis().getLocation()); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Product].[Drink].Children} ON COLUMNS,\n" + "{[Measures].[Store Sales]} ON ROWS\n" + "FROM [Sales]", mdxString); query.swapAxes(); } public void testSortDimension() throws Exception { 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"); productDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); query.validate(); assertEquals( Axis.ROWS, productDimension.getAxis().getLocation()); assertEquals( Axis.COLUMNS, measuresDimension.getAxis().getLocation()); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{{[Product].[Drink], [Product].[Drink].Children}} ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", mdxString); // Sort the products in ascending order. query.getDimension("Product").sort(SortOrder.DESC); SelectNode sortedMdx = query.getSelect(); String sortedMdxString = sortedMdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{Order({{[Product].[Drink], [Product].[Drink].Children}}, [Product].CurrentMember.Name, DESC)} ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", sortedMdxString); CellSet results = query.execute(); String s = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q3].[7]}\n" + "Axis #1:\n" + "{[Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Product].[Drink]}\n" + "{[Product].[Drink].[Dairy]}\n" + "{[Product].[Drink].[Beverages]}\n" + "{[Product].[Drink].[Alcoholic Beverages]}\n" + "Row #0: 4,409.58\n" + "Row #1: 629.69\n" + "Row #2: 2,477.02\n" + "Row #3: 1,302.87\n", s); } public void testSortMultipleDimension() throws Exception { 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"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); assertEquals( Axis.ROWS, timeDimension.getAxis().getLocation()); assertEquals( Axis.ROWS, productDimension.getAxis().getLocation()); assertEquals( Axis.COLUMNS, measuresDimension.getAxis().getLocation()); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "CrossJoin({[Time].[1997].[Q3].[7]}, [Product].[Drink].Children) ON ROWS\n" + "FROM [Sales]", mdxString); // Sort the products in ascending order. query.getDimension("Product").sort(SortOrder.DESC); SelectNode sortedMdx = query.getSelect(); String sortedMdxString = sortedMdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "CrossJoin({[Time].[1997].[Q3].[7]}, Order({[Product].[Drink].Children}, [Product].CurrentMember.Name, DESC)) ON ROWS\n" + "FROM [Sales]", sortedMdxString); CellSet results = query.execute(); String s = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Time].[1997].[Q3].[7], [Product].[Drink].[Dairy]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Drink].[Beverages]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Drink].[Alcoholic Beverages]}\n" + "Row #0: 629.69\n" + "Row #1: 2,477.02\n" + "Row #2: 1,302.87\n", s); // Just to be sure we execute the sort on a NON EMPTY axis again query.getAxis(Axis.ROWS).setNonEmpty(true); productDimension.clearInclusions(); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Food")); SelectNode sortedMdxNonEmpty = query.getSelect(); String sortedMdxNonEmptyString = sortedMdxNonEmpty.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "NON EMPTY CrossJoin({[Time].[1997].[Q3].[7]}, Order({[Product].[Food].Children}, [Product].CurrentMember.Name, DESC)) ON ROWS\n" + "FROM [Sales]", sortedMdxNonEmptyString); CellSet results2 = query.execute(); String s2 = TestContext.toString(results2); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Starchy Foods]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Snacks]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Snack Foods]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Seafood]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Produce]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Meat]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Frozen Foods]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Eggs]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Deli]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Dairy]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Canned Products]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Canned Foods]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Breakfast Foods]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Baking Goods]}\n" + "{[Time].[1997].[Q3].[7], [Product].[Food].[Baked Goods]}\n" + "Row #0: 1,059.06\n" + "Row #1: 1,248.92\n" + "Row #2: 6,342.01\n" + "Row #3: 383.20\n" + "Row #4: 7,084.85\n" + "Row #5: 304.61\n" + "Row #6: 5,027.30\n" + "Row #7: 930.70\n" + "Row #8: 2,222.69\n" + "Row #9: 2,896.81\n" + "Row #10: 250.84\n" + "Row #11: 3,301.38\n" + "Row #12: 551.95\n" + "Row #13: 3,232.70\n" + "Row #14: 1,487.74\n", s2); } public void testSelectionContext() throws Exception { 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"); productDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Product", "All Products")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include( Selection.Operator.MEMBER, nameList("Time", "Year", "1997")); Selection selection = timeDimension.include( Selection.Operator.CHILDREN, nameList("Time", "Year", "1997")); selection.addContext( productDimension.createSelection( nameList("Product", "All Products", "Drink"))); // [Store].[All Stores] QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( Selection.Operator.MEMBER, nameList("Store", "All Stores")); Selection children = storeDimension.include( Selection.Operator.CHILDREN, nameList("Store", "All Stores")); children.addContext( productDimension.createSelection( nameList("Product", "All Products", "Drink"))); children.addContext( timeDimension.createSelection(nameList("Time", "1997", "Q3"))); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); assertEquals( Axis.ROWS, productDimension.getAxis().getLocation()); assertEquals( Axis.COLUMNS, measuresDimension.getAxis().getLocation()); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "Hierarchize(Union(CrossJoin({[Product].[All Products], [Product].[All Products].Children}, CrossJoin({[Time].[1997]}, {[Store].[All Stores]})), Union(CrossJoin({[Product].[Drink]}, CrossJoin({[Time].[1997].[Q3]}, [Store].[All Stores].Children)), CrossJoin({[Product].[Drink]}, CrossJoin([Time].[1997].Children, {[Store].[All Stores]}))))) ON ROWS\n" + "FROM [Sales]", mdxString); // Sort the rows in ascending order. query.getAxis(Axis.ROWS).sort( SortOrder.ASC, nameList("Measures", "Store Sales")); SelectNode sortedMdx = query.getSelect(); String sortedMdxString = sortedMdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "Order(Hierarchize(Union(CrossJoin({[Product].[All Products], [Product].[All Products].Children}, CrossJoin({[Time].[1997]}, {[Store].[All Stores]})), Union(CrossJoin({[Product].[Drink]}, CrossJoin({[Time].[1997].[Q3]}, [Store].[All Stores].Children)), CrossJoin({[Product].[Drink]}, CrossJoin([Time].[1997].Children, {[Store].[All Stores]}))))), [Measures].[Store Sales], ASC) ON ROWS\n" + "FROM [Sales]", sortedMdxString); CellSet results = query.execute(); String s = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Product].[All Products], [Time].[1997], [Store].[All Stores]}\n" + "{[Product].[Drink], [Time].[1997], [Store].[All Stores]}\n" + "{[Product].[Drink], [Time].[1997].[Q1], [Store].[All Stores]}\n" + "{[Product].[Drink], [Time].[1997].[Q2], [Store].[All Stores]}\n" + "{[Product].[Drink], [Time].[1997].[Q3], [Store].[All Stores]}\n" + "{[Product].[Drink], [Time].[1997].[Q3], [Store].[Canada]}\n" + "{[Product].[Drink], [Time].[1997].[Q3], [Store].[Mexico]}\n" + "{[Product].[Drink], [Time].[1997].[Q3], [Store].[USA]}\n" + "{[Product].[Drink], [Time].[1997].[Q4], [Store].[All Stores]}\n" + "{[Product].[Non-Consumable], [Time].[1997], [Store].[All Stores]}\n" + "{[Product].[Food], [Time].[1997], [Store].[All Stores]}\n" + "Row #0: 565,238.13\n" + "Row #1: 48,836.21\n" + "Row #2: 11,585.80\n" + "Row #3: 11,914.58\n" + "Row #4: 11,994.00\n" + "Row #5: \n" + "Row #6: \n" + "Row #7: 11,994.00\n" + "Row #8: 13,341.83\n" + "Row #9: 107,366.33\n" + "Row #10: 409,035.59\n", s); } public void testComplexSelectionContext() throws Exception { 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"); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "All Products")); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "All Products")); QueryDimension timeDimension = query.getDimension("Time"); Selection selection = timeDimension.include( Selection.Operator.CHILDREN, nameList("Time", "Year", "1997")); selection.addContext( productDimension.createSelection( nameList("Product", "All Products"))); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); assertEquals( Axis.ROWS, productDimension.getAxis().getLocation()); assertEquals( Axis.ROWS, timeDimension.getAxis().getLocation()); assertEquals( Axis.COLUMNS, measuresDimension.getAxis().getLocation()); if (!Bug.BugOlap4j3106220Fixed) { return; } SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "Hierarchize(Union(CrossJoin({[Product].[All Products]}, [Time].[1997].Children), CrossJoin([Product].[All Products].Children, [Time].[1997].Children))) ON ROWS\n" + "FROM [Sales]", mdxString); CellSet results = query.execute(); String s = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Product].[All Products], [Time].[1997].[Q1]}\n" + "{[Product].[All Products], [Time].[1997].[Q2]}\n" + "{[Product].[All Products], [Time].[1997].[Q3]}\n" + "{[Product].[All Products], [Time].[1997].[Q4]}\n" + "{[Product].[Drink], [Time].[1997].[Q1]}\n" + "{[Product].[Drink], [Time].[1997].[Q2]}\n" + "{[Product].[Drink], [Time].[1997].[Q3]}\n" + "{[Product].[Drink], [Time].[1997].[Q4]}\n" + "{[Product].[Food], [Time].[1997].[Q1]}\n" + "{[Product].[Food], [Time].[1997].[Q2]}\n" + "{[Product].[Food], [Time].[1997].[Q3]}\n" + "{[Product].[Food], [Time].[1997].[Q4]}\n" + "{[Product].[Non-Consumable], [Time].[1997].[Q1]}\n" + "{[Product].[Non-Consumable], [Time].[1997].[Q2]}\n" + "{[Product].[Non-Consumable], [Time].[1997].[Q3]}\n" + "{[Product].[Non-Consumable], [Time].[1997].[Q4]}\n" + "Row #0: 139,628.35\n" + "Row #1: 132,666.27\n" + "Row #2: 140,271.89\n" + "Row #3: 152,671.62\n" + "Row #4: 11,585.80\n" + "Row #5: 11,914.58\n" + "Row #6: 11,994.00\n" + "Row #7: 13,341.83\n" + "Row #8: 101,261.32\n" + "Row #9: 95,436.00\n" + "Row #10: 101,807.60\n" + "Row #11: 110,530.67\n" + "Row #12: 26,781.23\n" + "Row #13: 25,315.69\n" + "Row #14: 26,470.29\n" + "Row #15: 28,799.12\n", s); } public void testSortAxis() throws Exception { 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"); productDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); query.validate(); assertEquals( Axis.ROWS, productDimension.getAxis().getLocation()); assertEquals( Axis.COLUMNS, measuresDimension.getAxis().getLocation()); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{{[Product].[Drink], [Product].[Drink].Children}} ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", mdxString); // Sort the rows in ascending order. query.getAxis(Axis.ROWS).sort( SortOrder.BASC, nameList("Measures", "Store Sales")); SelectNode sortedMdx = query.getSelect(); String sortedMdxString = sortedMdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "Order({{[Product].[Drink], [Product].[Drink].Children}}, [Measures].[Store Sales], BASC) ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", sortedMdxString); CellSet results = query.execute(); String s = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q3].[7]}\n" + "Axis #1:\n" + "{[Measures].[Store Sales]}\n" + "Axis #2:\n" + "{[Product].[Drink].[Dairy]}\n" + "{[Product].[Drink].[Alcoholic Beverages]}\n" + "{[Product].[Drink].[Beverages]}\n" + "{[Product].[Drink]}\n" + "Row #0: 629.69\n" + "Row #1: 1,302.87\n" + "Row #2: 2,477.02\n" + "Row #3: 4,409.58\n", s); } public void testDimensionsOrder() throws Exception { 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"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include( Selection.Operator.CHILDREN, nameList("Time", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "CrossJoin([Product].[Drink].Children, " + "CrossJoin({[Store].[USA], " + "[Store].[USA].Children}, " + "[Time].[1997].Children)) ON ROWS\n" + "FROM [Sales]", mdxString); // Push down the Products dimension. query.getAxis(Axis.ROWS).pushDown(0); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "CrossJoin({[Store].[USA], " + "[Store].[USA].Children}, " + "CrossJoin([Product].[Drink].Children, " + "[Time].[1997].Children)) ON ROWS\n" + "FROM [Sales]", mdxString); // Pull Up the Time dimension. query.getAxis(Axis.ROWS).pullUp(2); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "CrossJoin({[Store].[USA], " + "[Store].[USA].Children}, " + "CrossJoin([Time].[1997].Children, " + "[Product].[Drink].Children)) ON ROWS\n" + "FROM [Sales]", mdxString); } /** * Note: hierarchize mode only works when a single dimension is selected. */ public void testDimensionsHierarchize() throws Exception { Cube cube = getFoodmartCube("Sales"); if (cube == null) { fail("Could not find Sales cube"); } Query query = new Query("my query", cube); // create selections QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); storeDimension.setHierarchizeMode(HierarchizeMode.POST); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{Hierarchize({{[Store].[USA], " + "[Store].[USA].Children}}, POST)} ON ROWS\n" + "FROM [Sales]", mdxString); storeDimension.setHierarchizeMode(HierarchizeMode.PRE); query.validate(); mdx = query.getSelect(); mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{Hierarchize({{[Store].[USA], " + "[Store].[USA].Children}})} ON ROWS\n" + "FROM [Sales]", mdxString); } /** * This test makes sure that the generated MDX model is not affected * by subsequent operations performed on the source query model. */ public void testQueryVersusParseTreeIndependence() throws Exception { Cube cube = getFoodmartCube("Sales"); if (cube == null) { fail("Could not find Sales cube"); } // Setup a base query. Query query = new Query("my query", cube); QueryDimension productDimension = query.getDimension("Product"); productDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); assertEquals( Axis.ROWS, productDimension.getAxis().getLocation()); assertEquals( Axis.COLUMNS, measuresDimension.getAxis().getLocation()); // These variables are important. We will evaluate those // to decide if there are links between the MDX and the Query SelectNode originalMdx = query.getSelect(); String originalMdxString = originalMdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS,\n" + "{{[Product].[Drink], [Product].[Drink].Children}} ON ROWS\n" + "FROM [Sales]", originalMdxString); // change selections measuresDimension.include( Selection.Operator.SIBLINGS, nameList("Measures", "Customer Count")); productDimension.include( Selection.Operator.SIBLINGS, nameList( "Product", "All Products", "Drink", "Alcoholic Beverages")); // Add something to crossjoin with query.getAxis(Axis.ROWS).addDimension( query.getDimension("Gender")); query.getDimension("Gender").include( Operator.CHILDREN, nameList("Gender", "All Gender")); query.getAxis(null).addDimension( query.getDimension("Product")); query.validate(); // Check if the MDX object tree is still the same assertEquals(originalMdxString, originalMdx.toString()); } public void testExclusionModes() throws Exception { Cube cube = getFoodmartCube("Sales"); if (cube == null) { fail("Could not find Sales cube"); } // Setup a base query. Query query = new Query("my query", cube); QueryDimension productDimension = query.getDimension("Product"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink", "Beverages")); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Food", "Frozen Foods")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Sales Count")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); query.validate(); // Validate the generated MDX String mdxString = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Sales Count]} ON COLUMNS,\n" + "{[Product].[Drink].[Beverages].Children, [Product].[Food].[Frozen Foods].Children} ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", mdxString); // Validate the returned results CellSet results = query.execute(); String resultsString = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q3].[7]}\n" + "Axis #1:\n" + "{[Measures].[Sales Count]}\n" + "Axis #2:\n" + "{[Product].[Drink].[Beverages].[Carbonated Beverages]}\n" + "{[Product].[Drink].[Beverages].[Drinks]}\n" + "{[Product].[Drink].[Beverages].[Hot Beverages]}\n" + "{[Product].[Drink].[Beverages].[Pure Juice Beverages]}\n" + "{[Product].[Food].[Frozen Foods].[Breakfast Foods]}\n" + "{[Product].[Food].[Frozen Foods].[Frozen Desserts]}\n" + "{[Product].[Food].[Frozen Foods].[Frozen Entrees]}\n" + "{[Product].[Food].[Frozen Foods].[Meat]}\n" + "{[Product].[Food].[Frozen Foods].[Pizza]}\n" + "{[Product].[Food].[Frozen Foods].[Vegetables]}\n" + "Row #0: 103\n" + "Row #1: 65\n" + "Row #2: 125\n" + "Row #3: 100\n" + "Row #4: 143\n" + "Row #5: 185\n" + "Row #6: 68\n" + "Row #7: 81\n" + "Row #8: 105\n" + "Row #9: 212\n", resultsString); // Exclude the Carbonated Beverages because they are not good // for your health. query.getDimension("Product").exclude( nameList( "Product", "Drink", "Beverages", "Carbonated Beverages")); // Validate the generated MDX query.validate(); mdxString = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Sales Count]} ON COLUMNS,\n" + "{Except({[Product].[Drink].[Beverages].Children, [Product].[Food].[Frozen Foods].Children}, {[Product].[Drink].[Beverages].[Carbonated Beverages]})} ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", mdxString); // Validate the returned results results = query.execute(); resultsString = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q3].[7]}\n" + "Axis #1:\n" + "{[Measures].[Sales Count]}\n" + "Axis #2:\n" + "{[Product].[Drink].[Beverages].[Drinks]}\n" + "{[Product].[Drink].[Beverages].[Hot Beverages]}\n" + "{[Product].[Drink].[Beverages].[Pure Juice Beverages]}\n" + "{[Product].[Food].[Frozen Foods].[Breakfast Foods]}\n" + "{[Product].[Food].[Frozen Foods].[Frozen Desserts]}\n" + "{[Product].[Food].[Frozen Foods].[Frozen Entrees]}\n" + "{[Product].[Food].[Frozen Foods].[Meat]}\n" + "{[Product].[Food].[Frozen Foods].[Pizza]}\n" + "{[Product].[Food].[Frozen Foods].[Vegetables]}\n" + "Row #0: 65\n" + "Row #1: 125\n" + "Row #2: 100\n" + "Row #3: 143\n" + "Row #4: 185\n" + "Row #5: 68\n" + "Row #6: 81\n" + "Row #7: 105\n" + "Row #8: 212\n", resultsString); } public void testExclusionMultipleDimensionModes() throws Exception { Cube cube = getFoodmartCube("Sales"); if (cube == null) { fail("Could not find Sales cube"); } // Setup a base query. Query query = new Query("my query", cube); QueryDimension productDimension = query.getDimension("Product"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink", "Beverages")); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Food", "Frozen Foods")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Sales Count")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( Selection.Operator.MEMBER, nameList("Store", "USA")); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); // Validate the generated MDX String mdxString = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Sales Count]} ON COLUMNS,\n" + "Hierarchize(Union(CrossJoin({[Store].[USA]}, [Product].[Drink].[Beverages].Children), CrossJoin({[Store].[USA]}, [Product].[Food].[Frozen Foods].Children))) ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", mdxString); // Validate the returned results CellSet results = query.execute(); String resultsString = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q3].[7]}\n" + "Axis #1:\n" + "{[Measures].[Sales Count]}\n" + "Axis #2:\n" + "{[Store].[USA], [Product].[Drink].[Beverages].[Carbonated Beverages]}\n" + "{[Store].[USA], [Product].[Drink].[Beverages].[Drinks]}\n" + "{[Store].[USA], [Product].[Drink].[Beverages].[Hot Beverages]}\n" + "{[Store].[USA], [Product].[Drink].[Beverages].[Pure Juice Beverages]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Breakfast Foods]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Frozen Desserts]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Frozen Entrees]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Meat]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Pizza]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Vegetables]}\n" + "Row #0: 103\n" + "Row #1: 65\n" + "Row #2: 125\n" + "Row #3: 100\n" + "Row #4: 143\n" + "Row #5: 185\n" + "Row #6: 68\n" + "Row #7: 81\n" + "Row #8: 105\n" + "Row #9: 212\n", resultsString); // Exclude the Carbonated Beverages because they are not good // for your health. query.getDimension("Product").exclude( nameList( "Product", "Drink", "Beverages", "Carbonated Beverages")); // Validate the generated MDX query.validate(); mdxString = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Sales Count]} ON COLUMNS,\n" + "Hierarchize(Union(CrossJoin({[Store].[USA]}, Except({[Product].[Drink].[Beverages].Children}, {[Product].[Drink].[Beverages].[Carbonated Beverages]})), CrossJoin({[Store].[USA]}, Except({[Product].[Food].[Frozen Foods].Children}, {[Product].[Drink].[Beverages].[Carbonated Beverages]})))) ON ROWS\n" + "FROM [Sales]\n" + "WHERE {[Time].[1997].[Q3].[7]}", mdxString); // Validate the returned results results = query.execute(); resultsString = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Time].[1997].[Q3].[7]}\n" + "Axis #1:\n" + "{[Measures].[Sales Count]}\n" + "Axis #2:\n" + "{[Store].[USA], [Product].[Drink].[Beverages].[Drinks]}\n" + "{[Store].[USA], [Product].[Drink].[Beverages].[Hot Beverages]}\n" + "{[Store].[USA], [Product].[Drink].[Beverages].[Pure Juice Beverages]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Breakfast Foods]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Frozen Desserts]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Frozen Entrees]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Meat]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Pizza]}\n" + "{[Store].[USA], [Product].[Food].[Frozen Foods].[Vegetables]}\n" + "Row #0: 65\n" + "Row #1: 125\n" + "Row #2: 100\n" + "Row #3: 143\n" + "Row #4: 185\n" + "Row #5: 68\n" + "Row #6: 81\n" + "Row #7: 105\n" + "Row #8: 212\n", resultsString); } public void testCompoundFilter() throws Exception { Cube cube = getFoodmartCube("Sales"); if (cube == null) { fail("Could not find Sales cube"); } // Setup a base query. Query query = new Query("my query", cube); QueryDimension productDimension = query.getDimension("Product"); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "Drink", "Beverages")); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "Food", "Frozen Foods")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Sales Count")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( Selection.Operator.MEMBER, nameList("Store", "USA")); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.FILTER).addDimension(productDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.validate(); // Validate the generated MDX String mdxString = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Sales Count]} ON COLUMNS,\n" + "{[Store].[USA]} ON ROWS\n" + "FROM [Sales]\n" + "WHERE Hierarchize(Union(CrossJoin({[Product].[Drink].[Beverages]}, {[Time].[1997].[Q3].[7]}), CrossJoin({[Product].[Food].[Frozen Foods]}, {[Time].[1997].[Q3].[7]})))", mdxString); // Validate the returned results CellSet results = query.execute(); String resultsString = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{[Product].[Drink].[Beverages], [Time].[1997].[Q3].[7]}\n" + "{[Product].[Food].[Frozen Foods], [Time].[1997].[Q3].[7]}\n" + "Axis #1:\n" + "{[Measures].[Sales Count]}\n" + "Axis #2:\n" + "{[Store].[USA]}\n" + "Row #0: 1,187\n", resultsString); } public void testMultipleHierarchyConsistency() throws Exception { Cube cube = getFoodmartCube("Sales"); if (cube == null) { fail("Could not find Sales cube"); } // Setup a base query. Query query = new Query("my query", cube); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.setHierarchyConsistent(true); timeDimension.include(nameList("Time.Weekly", "1997", "10", "23")); timeDimension.include(nameList("Time.Weekly", "1997", "10", "28")); timeDimension.include(nameList("Time.Weekly", "Year", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Sales Count")); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.validate(); // Validate the generated MDX String mdxString = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Sales Count]} ON COLUMNS,\n" + "{{[Time.Weekly].[1997]}, Filter({{[Time.Weekly].[1997].[10].[23], [Time.Weekly].[1997].[10].[28]}}, (Ancestor([Time.Weekly].CurrentMember, [Time.Weekly].[Year]) IN {[Time.Weekly].[1997]}))} ON ROWS\n" + "FROM [Sales]", mdxString); // Validate the returned results CellSet results = query.execute(); String resultsString = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Sales Count]}\n" + "Axis #2:\n" + "{[Time.Weekly].[1997]}\n" + "{[Time.Weekly].[1997].[10].[23]}\n" + "{[Time.Weekly].[1997].[10].[28]}\n" + "Row #0: 86,837\n" + "Row #1: 123\n" + "Row #2: \n", resultsString); query.validate(); } public void testHierarchyConsistency() throws Exception { Cube cube = getFoodmartCube("Sales"); if (cube == null) { fail("Could not find Sales cube"); } // Setup a base query. Query query = new Query("my query", cube); QueryDimension productDimension = query.getDimension("Product"); productDimension.setHierarchyConsistent(true); NamedList productLevels = productDimension.getDimension() .getDefaultHierarchy().getLevels(); Level productLevel = productLevels.get("Product Category"); productDimension.include(productLevel); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "Food", "Deli")); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "Food", "Dairy")); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "Product Family", "Food")); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "All Products")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.setHierarchyConsistent(true); timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); timeDimension.include(nameList("Time", "Year", "1997", "Q4", "11")); timeDimension.include(nameList("Time", "Year", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Sales Count")); query.getAxis(Axis.COLUMNS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.validate(); // Validate the generated MDX String mdxString = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{{[Product].[All Products]}, {[Product].[Food]}, Filter({{[Product].[Food].[Deli], [Product].[Food].[Dairy]}}, (Ancestor([Product].CurrentMember, [Product].[Product Family]) IN {[Product].[Food]})), Filter({{[Product].[Product Category].Members}}, ((Ancestor([Product].CurrentMember, [Product].[Product Family]) IN {[Product].[Food]}) AND (Ancestor([Product].CurrentMember, [Product].[Product Department]) IN {[Product].[Food].[Deli], [Product].[Food].[Dairy]})))} ON COLUMNS,\n" + "{{[Time].[1997]}, Filter({{[Time].[1997].[Q3].[7], [Time].[1997].[Q4].[11]}}, (Ancestor([Time].CurrentMember, [Time].[Year]) IN {[Time].[1997]}))} ON ROWS\n" + "FROM [Sales]", mdxString); // Validate the returned results CellSet results = query.execute(); String resultsString = TestContext.toString(results); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Product].[All Products]}\n" + "{[Product].[Food]}\n" + "{[Product].[Food].[Deli]}\n" + "{[Product].[Food].[Dairy]}\n" + "{[Product].[Food].[Dairy].[Dairy]}\n" + "{[Product].[Food].[Deli].[Meat]}\n" + "{[Product].[Food].[Deli].[Side Dishes]}\n" + "Axis #2:\n" + "{[Time].[1997]}\n" + "{[Time].[1997].[Q3].[7]}\n" + "{[Time].[1997].[Q4].[11]}\n" + "Row #0: 266,773\n" + "Row #0: 191,940\n" + "Row #0: 12,037\n" + "Row #0: 12,885\n" + "Row #0: 12,885\n" + "Row #0: 9,433\n" + "Row #0: 2,604\n" + "Row #1: 23,763\n" + "Row #1: 17,036\n" + "Row #1: 1,050\n" + "Row #1: 1,229\n" + "Row #1: 1,229\n" + "Row #1: 847\n" + "Row #1: 203\n" + "Row #2: 25,270\n" + "Row #2: 18,278\n" + "Row #2: 1,312\n" + "Row #2: 1,232\n" + "Row #2: 1,232\n" + "Row #2: 1,033\n" + "Row #2: 279\n", resultsString); query.validate(); query.getAxis(Axis.ROWS).addDimension(measuresDimension); productDimension.clearInclusions(); productDimension.include( Selection.Operator.MEMBER, nameList("Product", "Product Family", "Food")); // Validate the generated MDX String mdxString2 = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Product].[Food]} ON COLUMNS,\n" + "Hierarchize(Union(CrossJoin(Filter({[Time].[1997].[Q3].[7]}, (Ancestor([Time].CurrentMember, [Time].[Year]) IN {[Time].[1997]})), {[Measures].[Sales Count]}), Union(CrossJoin(Filter({[Time].[1997].[Q4].[11]}, (Ancestor([Time].CurrentMember, [Time].[Year]) IN {[Time].[1997]})), {[Measures].[Sales Count]}), CrossJoin({[Time].[1997]}, {[Measures].[Sales Count]})))) ON ROWS\n" + "FROM [Sales]", mdxString2); // Validate the returned results CellSet results2 = query.execute(); String resultsString2 = TestContext.toString(results2); TestContext.assertEqualsVerbose( "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Product].[Food]}\n" + "Axis #2:\n" + "{[Time].[1997], [Measures].[Sales Count]}\n" + "{[Time].[1997].[Q3].[7], [Measures].[Sales Count]}\n" + "{[Time].[1997].[Q4].[11], [Measures].[Sales Count]}\n" + "Row #0: 62,445\n" + "Row #1: 5,552\n" + "Row #2: 5,944\n", resultsString2); QueryDimension customerDimension = query.getDimension("Customers"); customerDimension.setHierarchyConsistent(true); NamedList customerLevels = customerDimension.getDimension() .getDefaultHierarchy().getLevels(); Level country = customerLevels.get("Country"); Level state = customerLevels.get("State Province"); customerDimension.include(country); customerDimension.include(state); query.getAxis(Axis.ROWS).removeDimension(timeDimension); query.getAxis(Axis.ROWS).addDimension(customerDimension); String mdxString3 = query.getSelect().toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Product].[Food]} ON COLUMNS,\n" + "Hierarchize(Union(CrossJoin({[Measures].[Sales Count]}, [Customers].[Country].Members), CrossJoin({[Measures].[Sales Count]}, [Customers].[State Province].Members))) ON ROWS\n" + "FROM [Sales]", mdxString3); } public void testNonMandatoryQueryAxis() throws Exception { 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"); productDimension.include( Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); storeDimension.setHierarchizeMode(HierarchizeMode.POST); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include( Selection.Operator.CHILDREN, nameList("Time", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); measuresDimension.include(nameList("Measures", "Store Sales")); //query.getAxis(Axis.ROWS).addDimension(productDimension); //query.getAxis(Axis.ROWS).addDimension(storeDimension); //query.getAxis(Axis.ROWS).addDimension(timeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); //query.validate(); SelectNode mdx = query.getSelect(); String mdxString = mdx.toString(); TestContext.assertEqualsVerbose( "SELECT\n" + "{[Measures].[Store Sales]} ON COLUMNS\n" + "FROM [Sales]", mdxString); try { query.validate(); fail(); } catch (OlapException e) { assertEquals(0, e.getCause().getMessage().indexOf( "A valid Query requires at least one " + "dimension on the rows axis.")); } } public static void main(String args[]) throws Exception { OlapTest olapTest = new OlapTest(); olapTest.testModel(); } } // End OlapTest.java olap4j-1.0.1.500/testsrc/org/olap4j/impl/0000755000175000017500000000000011421322444017506 5ustar drazzibdrazzibolap4j-1.0.1.500/testsrc/org/olap4j/impl/Olap4jUtilTest.java0000644000175000017500000006354611707254766023240 0ustar drazzibdrazzib/* // $Id: Olap4jUtilTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import org.olap4j.mdx.*; import junit.framework.TestCase; import java.util.*; /** * Tests for methods in {@link org.olap4j.impl.Olap4jUtil}. * * @author jhyde * @version $Id: Olap4jUtilTest.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 12, 2007 */ public class Olap4jUtilTest extends TestCase { //~ Helper methods ========================================================= /** * Asserts that two integer arrays have equal length and contents. * * @param expected Expected integer array * @param actual Actual integer array */ public void assertEqualsArray(int[] expected, int[] actual) { if (expected == null) { assertEquals(expected, actual); } else { List expectedList = new ArrayList(); for (int i : expected) { expectedList.add(i); } List actualList = new ArrayList(); for (int i : actual) { actualList.add(i); } assertEquals(expectedList, actualList); } } //~ Tests follow =========================================================== /** * Tests {@link Olap4jUtil#camelToUpper}. */ public void testCamel() { assertEquals( "FOO_BAR", Olap4jUtil.camelToUpper("FooBar")); assertEquals( "FOO_BAR", Olap4jUtil.camelToUpper("fooBar")); assertEquals( "URL", Olap4jUtil.camelToUpper("URL")); assertEquals( "URLTO_CLICK_ON", Olap4jUtil.camelToUpper("URLtoClickOn")); assertEquals( "", Olap4jUtil.camelToUpper("")); } /** * Tests {@link Olap4jUtil#equal}. */ public void testEqual() { assertTrue(Olap4jUtil.equal("x", "x")); assertFalse(Olap4jUtil.equal("x", "y")); assertTrue(Olap4jUtil.equal("xy", "x" + "y")); assertTrue(Olap4jUtil.equal(null, null)); assertFalse(Olap4jUtil.equal(null, "x")); assertFalse(Olap4jUtil.equal("x", null)); final Integer TWO = 1 + 1; assertTrue(Olap4jUtil.equal(2, TWO)); } /** * Tests {@link Olap4jUtil#wildcardToRegexp(java.util.List)}. */ public void testWildcard() { assertEquals( ".\\QFoo\\E.|\\QBar\\E.*\\QBAZ\\E", Olap4jUtil.wildcardToRegexp( Arrays.asList("_Foo_", "Bar%BAZ"))); } /** * Tests {@link org.olap4j.impl.CoordinateIterator}. */ public void testCoordinateIterator() { // no axes, should produce one result CoordinateIterator iter = new CoordinateIterator(new int[]{}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {}); // one axis of length n, should produce n elements iter = new CoordinateIterator(new int[]{2}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {0}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {1}); assertFalse(iter.hasNext()); // one axis of length 0, should produce 0 elements iter = new CoordinateIterator(new int[]{0}); assertFalse(iter.hasNext()); // two axes of length 0, should produce 0 elements iter = new CoordinateIterator(new int[]{0, 0}); assertFalse(iter.hasNext()); // five axes of length 0, should produce 0 elements iter = new CoordinateIterator(new int[]{0, 0, 0, 0, 0}); assertFalse(iter.hasNext()); // two axes, neither empty iter = new CoordinateIterator(new int[]{2, 3}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {0, 0}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {0, 1}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {0, 2}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {1, 0}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {1, 1}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {1, 2}); assertFalse(iter.hasNext()); // three axes, one of length 0, should produce 0 elements iter = new CoordinateIterator(new int[]{10, 0, 2}); assertFalse(iter.hasNext()); iter = new CoordinateIterator(new int[]{0, 10, 2}); assertFalse(iter.hasNext()); // if any axis has negative length, produces 0 elements iter = new CoordinateIterator(new int[]{3, 4, 5, -6, 7}); assertFalse(iter.hasNext()); iter = new CoordinateIterator(new int[]{3, 4, 5, 6, -7}); assertFalse(iter.hasNext()); iter = new CoordinateIterator(new int[]{-3, 4, 5, 6, 7}); assertFalse(iter.hasNext()); } /** * Tests a little-endian {@link org.olap4j.impl.CoordinateIterator}. */ public void testCoordinateIteratorLittleEndian() { // two axes, neither empty CoordinateIterator iter = new CoordinateIterator(new int[]{2, 3}, true); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {0, 0}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {1, 0}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {0, 1}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {1, 1}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {0, 2}); assertTrue(iter.hasNext()); assertEqualsArray(iter.next(), new int[] {1, 2}); assertFalse(iter.hasNext()); } /** * Tests {@link org.olap4j.impl.UnmodifiableArrayList}. */ public void testUnmodifiableArrayList() { String[] a = {"x", "y"}; final UnmodifiableArrayList list = new UnmodifiableArrayList(a); final UnmodifiableArrayList copyList = UnmodifiableArrayList.asCopyOf(a); assertEquals(2, list.size()); assertEquals("x", list.get(0)); assertEquals("y", list.get(1)); try { final String s = list.get(2); fail("expected error, got " + s); } catch (IndexOutOfBoundsException e) { // ok } // check various equality relations assertTrue(list.equals(copyList)); assertTrue(copyList.equals(list)); assertTrue(list.equals(list)); assertEquals(list.hashCode(), copyList.hashCode()); assertEquals(Arrays.asList(a), list); assertEquals(list, Arrays.asList(a)); String sum = ""; for (String s : list) { sum = sum + s; } assertEquals("xy", sum); final Iterator iterator = list.iterator(); assertTrue(iterator.hasNext()); assertEquals("x", iterator.next()); try { iterator.remove(); fail("expected error"); } catch (UnsupportedOperationException e) { // ok } a[1] = "z"; assertTrue(iterator.hasNext()); assertEquals("z", iterator.next()); assertFalse(iterator.hasNext()); // modifying the array modifies the list, but not the clone list assertEquals("z", list.get(1)); assertEquals("y", copyList.get(1)); // test the of(Collection) method final List arrayList = new ArrayList(); arrayList.add("foo"); arrayList.add("bar"); final UnmodifiableArrayList list3 = UnmodifiableArrayList.of(arrayList); assertEquals(2, list3.size()); assertEquals(arrayList, list3); assertEquals(arrayList.hashCode(), list3.hashCode()); } /** * Unit test for {@link Olap4jUtil#parseUniqueName(String)}. */ public void testUniqueNameToStringArray() { List a; a = Olap4jUtil.parseUniqueName("foo.bar"); assertEquals(2, a.size()); assertEquals("foo", a.get(0)); assertEquals("bar", a.get(1)); // with spaces a = Olap4jUtil.parseUniqueName("[foo bar].[baz]"); assertEquals(2, a.size()); assertEquals("foo bar", a.get(0)); assertEquals("baz", a.get(1)); // with dots a = Olap4jUtil.parseUniqueName("[foo.bar].[baz]"); assertEquals(3, a.size()); assertEquals("foo", a.get(0)); assertEquals("bar", a.get(1)); assertEquals("baz", a.get(2)); // Unique names can have '&'s in them. I'm not sure that this is the // behavior we want, but this test at least documents the current // behavior. a = Olap4jUtil.parseUniqueName("[customers].&[baz]&[2]"); assertEquals(5, a.size()); assertEquals("customers", a.get(0)); assertEquals("&", a.get(1)); assertEquals("baz", a.get(2)); assertEquals("&", a.get(3)); assertEquals("2", a.get(4)); } public void testParseFormattedCellValue() { // no formatting checkParseFormattedCellValue("123", "123", "{}"); // no formatting, value contains '|' checkParseFormattedCellValue("12|3", "12|3", "{}"); // empty string checkParseFormattedCellValue("", "", "{}"); // one property checkParseFormattedCellValue("|123|style=red|", "123", "{style=red}"); // multiple properties checkParseFormattedCellValue( "|123|style=red|arrow=up|", "123", "{arrow=up, style=red}"); // invalid property value -- we don't care checkParseFormattedCellValue( "|123|style=red|arrow=asdas|", "123", "{arrow=asdas, style=red}"); // empty value checkParseFormattedCellValue("||style=red|", "", "{style=red}"); // empty property value checkParseFormattedCellValue( "|abc|style=|foo=bar|", "abc", "{foo=bar, style=}"); // REVIEW: spaces in property value cause it not to be recognized as a // property checkParseFormattedCellValue( "|abc|style=xx|foo=bar baz|", "abcfoo=bar baz", "{style=xx}"); // spaces in property value recognized, provided property value is // enclosed in quotes checkParseFormattedCellValue( "|abc|style=xx|foo='bar baz'|", "abc", "{foo=bar baz, style=xx}"); // '=' in property value checkParseFormattedCellValue( "|abc|style=xx|foo=baz=zz|", "abc", "{foo=baz=zz, style=xx}"); // missing '|' terminator checkParseFormattedCellValue( "|abc|foo=bar", "abc", "{foo=bar}"); // null value try { String s = Olap4jUtil.parseFormattedCellValue( null, new HashMap()); fail("expected NPE, got " + s); } catch (NullPointerException e) { // ok } } private void checkParseFormattedCellValue( String formattedCellValue, String expectedCellValue, String expectedProperties) { final TreeMap map = new TreeMap(); final String cellValue = Olap4jUtil.parseFormattedCellValue(formattedCellValue, map); assertEquals("cell value", expectedCellValue, cellValue); assertEquals("properties", expectedProperties, map.toString()); } /** * Tests the {@link IdentifierNode#parseIdentifier} method. */ public void testParseIdentifier() { List segments = IdentifierParser.parseIdentifier( "[string].[with].[a [bracket]] in it]"); assertEquals(3, segments.size()); assertEquals("a [bracket] in it", segments.get(2).getName()); segments = IdentifierParser.parseIdentifier( "[Worklog].[All].[calendar-[LANGUAGE]].js]"); assertEquals(3, segments.size()); assertEquals("calendar-[LANGUAGE].js", segments.get(2).getName()); // allow spaces before, after and between segments = IdentifierParser.parseIdentifier(" [foo] . [bar].[baz] "); assertEquals(3, segments.size()); assertEquals("foo", segments.get(0).getName()); // first segment not quoted segments = IdentifierParser.parseIdentifier("Time.1997.[Q3]"); assertEquals(3, segments.size()); assertEquals("Time", segments.get(0).getName()); assertEquals("1997", segments.get(1).getName()); assertEquals("Q3", segments.get(2).getName()); // spaces ignored after unquoted segment segments = IdentifierParser.parseIdentifier("[Time . Weekly ] . 1997 . [Q3]"); assertEquals(3, segments.size()); assertEquals("Time . Weekly ", segments.get(0).getName()); assertEquals("1997", segments.get(1).getName()); assertEquals("Q3", segments.get(2).getName()); // identifier ending in '.' is invalid try { segments = IdentifierParser.parseIdentifier("[foo].[bar]."); fail("expected exception, got " + segments); } catch (IllegalArgumentException e) { assertEquals( "Expected identifier after '.', in member identifier " + "'[foo].[bar].'", e.getMessage()); } try { segments = IdentifierParser.parseIdentifier("[foo].[bar"); fail("expected exception, got " + segments); } catch (IllegalArgumentException e) { assertEquals( "Expected ']', in member identifier '[foo].[bar'", e.getMessage()); } try { segments = IdentifierParser.parseIdentifier("[Foo].[Bar], [Baz]"); fail("expected exception, got " + segments); } catch (IllegalArgumentException e) { assertEquals( "Invalid member identifier '[Foo].[Bar], [Baz]'", e.getMessage()); } // test case for bug 3036629, "Patch 328 breaks test". segments = IdentifierParser.parseIdentifier( "[ProductFilterDim].[Product Main Group Name].&[Maingroup (xyz)]"); assertEquals(3, segments.size()); final IdentifierSegment s0 = segments.get(0); assertEquals("ProductFilterDim", s0.getName()); assertEquals(Quoting.QUOTED, s0.getQuoting()); final IdentifierSegment s1 = segments.get(1); assertEquals("Product Main Group Name", s1.getName()); assertEquals(Quoting.QUOTED, s1.getQuoting()); assertTrue(segments.get(2) instanceof KeySegment); KeySegment s2 = (KeySegment) segments.get(2); assertEquals(1, s2.getKeyParts().size()); final NameSegment s2k0 = s2.getKeyParts().get(0); assertEquals("Maingroup (xyz)", s2k0.getName()); assertEquals(Quoting.QUOTED, s2k0.getQuoting()); } /** * Advanced test for the {@link IdentifierNode#parseIdentifier} method. */ public void testParseIdentifierAdvanced() { List segments; // detailed example, per javadoc // // A more complex example illustrates a compound key. The identifier // [Customers].[City].&[San Francisco]&CA&USA.&[cust1234] // contains four segments as follows: // // * Segment #0 is QUOTED, name "Customers" // * Segment #1 is QUOTED, name "City" // * Segment #2 is a KEY. It has 3 sub-segments: // ** Sub-segment #0 is QUOTED, name "San Francisco" // ** Sub-segment #1 is UNQUOTED, name "CA" // ** Sub-segment #2 is UNQUOTED, name "USA" // * Segment #3 is a KEY. It has 1 sub-segment: // ** Sub-segment #0 is QUOTED, name "cust1234" segments = IdentifierParser.parseIdentifier( "[Customers].[City].&[San Francisco]&CA&USA.&[cust1234]"); assertEquals(4, segments.size()); final IdentifierSegment s0 = segments.get(0); assertEquals("Customers", s0.getName()); assertEquals(Quoting.QUOTED, s0.getQuoting()); final IdentifierSegment s1 = segments.get(1); assertEquals("City", s1.getName()); assertEquals(Quoting.QUOTED, s1.getQuoting()); assertTrue(segments.get(2) instanceof KeySegment); KeySegment s2 = (KeySegment) segments.get(2); assertEquals(3, s2.getKeyParts().size()); final NameSegment s2k0 = s2.getKeyParts().get(0); assertEquals("San Francisco", s2k0.getName()); assertEquals(Quoting.QUOTED, s2k0.getQuoting()); final NameSegment s2k1 = s2.getKeyParts().get(1); assertEquals("CA", s2k1.getName()); assertEquals(Quoting.QUOTED, s2k0.getQuoting()); final NameSegment s2k2 = s2.getKeyParts().get(0); assertEquals("San Francisco", s2k2.getName()); assertEquals(Quoting.QUOTED, s2k2.getQuoting()); KeySegment s3 = (KeySegment) segments.get(3); assertNull(s3.getName()); assertEquals(1, s3.getKeyParts().size()); final NameSegment s3k0 = s3.getKeyParts().get(0); assertEquals("cust1234", s3k0.getName()); assertEquals(Quoting.QUOTED, s3k0.getQuoting()); } /** * Tests the {@link IdentifierParser#parseIdentifierList(String)} method. */ public void testParseIdentifierList() { List> list; list = IdentifierParser.parseIdentifierList("{foo, baz.baz}"); assertEquals(2, list.size()); assertEquals(1, list.get(0).size()); assertEquals(2, list.get(1).size()); // now without braces list = IdentifierParser.parseIdentifierList("foo, baz.baz"); assertEquals(2, list.size()); // now with spaces list = IdentifierParser.parseIdentifierList(" { foo , baz.baz } "); assertEquals(2, list.size()); // now with spaces & without braces list = IdentifierParser.parseIdentifierList(" { foo , baz.baz } "); assertEquals(2, list.size()); // now with keys list = IdentifierParser.parseIdentifierList( "{foo , baz.&k0&k1.&m0 . boo}"); assertEquals(2, list.size()); assertEquals(1, list.get(0).size()); assertEquals(4, list.get(1).size()); assertEquals("baz", list.get(1).get(0).getName()); final IdentifierSegment id1s1 = list.get(1).get(1); assertEquals(2, id1s1.getKeyParts().size()); assertEquals("k0", id1s1.getKeyParts().get(0).getName()); assertEquals("k1", id1s1.getKeyParts().get(1).getName()); final IdentifierSegment id1s2 = list.get(1).get(2); assertEquals(1, id1s2.getKeyParts().size()); assertEquals("m0", id1s2.getKeyParts().get(0).getName()); assertEquals("boo", list.get(1).get(3).getName()); assertEquals("[baz, &k0&k1, &m0, boo]", list.get(1).toString()); // now with mismatched braces try { list = IdentifierParser.parseIdentifierList(" { foo , baz.baz "); fail("expected error, got " + list); } catch (RuntimeException e) { assertEquals( "mismatched '{' and '}' in ' { foo , baz.baz '", e.getMessage()); } // now with mismatched braces try { list = IdentifierParser.parseIdentifierList(" foo , baz.baz } "); fail("expected error, got " + list); } catch (RuntimeException e) { assertEquals( "mismatched '{' and '}' in ' foo , baz.baz } '", e.getMessage()); } // empty string yields empty list list = IdentifierParser.parseIdentifierList("{}"); assertEquals(0, list.size()); list = IdentifierParser.parseIdentifierList(" { } "); assertEquals(0, list.size()); list = IdentifierParser.parseIdentifierList(""); assertEquals(0, list.size()); list = IdentifierParser.parseIdentifierList(" \t\n"); assertEquals(0, list.size()); } public void testParseTupleList() { final StringBuilder buf = new StringBuilder(); final IdentifierParser.Builder builder = new IdentifierParser.Builder() { public void tupleComplete() { buf.append(""); } public void memberComplete() { buf.append(""); } public void segmentComplete( ParseRegion region, String name, Quoting quoting, Syntax syntax) { if (quoting == Quoting.QUOTED) { buf.append("[").append(name).append("]"); } else { buf.append(name); } buf.append("<").append(syntax).append(">"); } }; // Set of tuples. buf.setLength(0); IdentifierParser.parseTupleList( builder, "{([Foo]), ([Bar].[Baz].&k0&[k1].&[k2])}"); assertEquals( "[Foo]" + "[Bar][Baz]" + "k0[k1][k2]" + "", buf.toString()); // Set of members. buf.setLength(0); try { IdentifierParser.parseTupleList(builder, "{[Foo], [Bar].[Baz]}"); fail("expected error"); } catch (IllegalArgumentException e) { assertEquals( "expected '(' at position 2 in '{[Foo], [Bar].[Baz]}'", e.getMessage()); } // Empty set. // TODO: this shouldn't fail buf.setLength(0); try { IdentifierParser.parseTupleList(builder, "{ }"); fail("expected error"); } catch (IllegalArgumentException e) { assertEquals( "expected '(' at position 3 in '{ }'", e.getMessage()); } // Empty set (no brackets). // TODO: this shouldn't fail buf.setLength(0); try { IdentifierParser.parseTupleList(builder, ""); fail("expected error"); } catch (IllegalArgumentException e) { assertEquals( "expected '{' at position 1 in ''", e.getMessage()); } // Set of mixed tuples & members. // TODO: this shouldn't fail buf.setLength(0); try { IdentifierParser.parseTupleList( builder, "{([A], [Tuple]), [A].Member}"); } catch (IllegalArgumentException e) { assertEquals( "expected '(' at position 18 in '{([A], [Tuple]), [A].Member}'", e.getMessage()); } // Same, but no braces. // TODO: this shouldn't fail buf.setLength(0); try { IdentifierParser.parseTupleList( builder, "([A], [Tuple]), [A].Member"); } catch (IllegalArgumentException e) { assertEquals( "expected '{' at position 1 in '([A], [Tuple]), [A].Member'", e.getMessage()); } } /** * Unit test for {@link LcidLocale#lcidToLocale(short)}. */ public void testLcidToLocale() { assertEquals( "en_US", LcidLocale.lcidToLocale((short) 0x0409).toString()); assertEquals("en_US", LcidLocale.lcidToLocale((short) 1033).toString()); assertEquals("fr", LcidLocale.lcidToLocale((short) 0x040c).toString()); assertEquals("en_GB", LcidLocale.lcidToLocale((short) 2057).toString()); } /** * Unit test for {@link LcidLocale#localeToLcid(java.util.Locale)}. */ public void testLocaleToLcid() { assertEquals(0x0409, LcidLocale.localeToLcid(Locale.US)); assertEquals(1033, LcidLocale.localeToLcid(Locale.US)); assertEquals(0x040c, LcidLocale.localeToLcid(Locale.FRENCH)); assertEquals(0x040c, LcidLocale.localeToLcid(Locale.FRANCE)); assertEquals(2060, LcidLocale.localeToLcid(new Locale("fr", "BE"))); assertEquals(2057, LcidLocale.localeToLcid(Locale.UK)); assertEquals(1031, LcidLocale.localeToLcid(Locale.GERMAN)); assertEquals(1031, LcidLocale.localeToLcid(Locale.GERMANY)); } /** * Unit test for {@link LcidLocale#parseLocale(String)} method. */ public void testParseLocale() { Locale[] locales = { Locale.CANADA, Locale.CANADA_FRENCH, Locale.getDefault(), Locale.US, Locale.TRADITIONAL_CHINESE, }; for (Locale locale : locales) { assertEquals(locale, LcidLocale.parseLocale(locale.toString())); } // Example locale names in Locale.toString() javadoc. String[] localeNames = { "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC" }; for (String localeName : localeNames) { assertEquals( localeName, LcidLocale.parseLocale(localeName).toString()); } } } // End Olap4jUtilTest.java olap4j-1.0.1.500/testsrc/org/olap4j/impl/ConnectStringParserTest.java0000644000175000017500000003322711707254766025177 0ustar drazzibdrazzib/* // $Id: ConnectStringParserTest.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import junit.framework.TestCase; import java.util.Map; /** * Unit test for {@link org.olap4j.impl.ConnectStringParser}. * * @version $Id: ConnectStringParserTest.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class ConnectStringParserTest extends TestCase { public ConnectStringParserTest(String s) { super(s); } public void testParseConnectStringSimple() { // Simple connect string Map properties = ConnectStringParser.parseConnectString("foo=x;bar=y;foo=z"); assertEquals("y", properties.get("bar")); assertEquals("y", properties.get("BAR")); // get is case-insensitive assertNull(properties.get(" bar")); // get does not ignore spaces assertEquals("z", properties.get("foo")); // later occurrence overrides assertNull(properties.get("kipper")); assertEquals(2, properties.size()); assertEquals("foo=z; bar=y", properties.toString()); } public void testParseConnectStringComplex() { Map properties = ConnectStringParser.parseConnectString( "normalProp=value;" + "emptyValue=;" + " spaceBeforeProp=abc;" + " spaceBeforeAndAfterProp =def;" + " space in prop = foo bar ;" + "equalsInValue=foo=bar;" + "semiInProp;Name=value;" + " singleQuotedValue = 'single quoted value ending in space ' ;" + " doubleQuotedValue = \"=double quoted value preceded by equals\" ;" + " singleQuotedValueWithSemi = 'one; two';" + " singleQuotedValueWithSpecials = 'one; two \"three''four=five'"); assertEquals(11, properties.size()); String value; value = properties.get("normalProp"); assertEquals("value", value); value = properties.get("emptyValue"); assertEquals("", value); // empty string, not null! value = properties.get("spaceBeforeProp"); assertEquals("abc", value); value = properties.get("spaceBeforeAndAfterProp"); assertEquals("def", value); value = properties.get("space in prop"); assertEquals(value, "foo bar"); value = properties.get("equalsInValue"); assertEquals("foo=bar", value); value = properties.get("semiInProp;Name"); assertEquals("value", value); value = properties.get("singleQuotedValue"); assertEquals("single quoted value ending in space ", value); value = properties.get("doubleQuotedValue"); assertEquals("=double quoted value preceded by equals", value); value = properties.get("singleQuotedValueWithSemi"); assertEquals(value, "one; two"); value = properties.get("singleQuotedValueWithSpecials"); assertEquals(value, "one; two \"three'four=five"); } public void testConnectStringMore() { p("singleQuote=''''", "singleQuote", "'"); p("doubleQuote=\"\"\"\"", "doubleQuote", "\""); p("empty= ;foo=bar", "empty", ""); } /** * Testcase for bug 1938151, "StringIndexOutOfBoundsException instead of a * meaningful error" */ public void testBug1938151() { Map properties; // ends in semi properties = ConnectStringParser.parseConnectString("foo=true; bar=xxx;"); assertEquals(2, properties.size()); // ends in semi+space properties = ConnectStringParser.parseConnectString("foo=true; bar=xxx; "); assertEquals(2, properties.size()); // ends in space properties = ConnectStringParser.parseConnectString(" "); assertEquals(0, properties.size()); // actual testcase for bug properties = ConnectStringParser.parseConnectString( "provider=mondrian; JdbcDrivers=org.hsqldb.jdbcDriver;" + "Jdbc=jdbc:hsqldb:./sql/sampledata;" + "Catalog=C:\\cygwin\\home\\src\\jfreereport\\engines\\classic\\extensions-mondrian\\demo\\steelwheels.mondrian.xml;" + "JdbcUser=sa; JdbcPassword=; "); assertEquals(6, properties.size()); assertEquals("", properties.get("JdbcPassword")); } /** * Checks that connectString contains a property called * name, whose value is value. * * @param connectString Connect string * @param name Name of property * @param expectedValue Expected value of property */ void p(String connectString, String name, String expectedValue) { Map properties = ConnectStringParser.parseConnectString(connectString); String value = properties.get(name); assertEquals(expectedValue, value); } public void testOleDbSpec() { p("Provider='MSDASQL'", "Provider", "MSDASQL"); p("Provider='MSDASQL.1'", "Provider", "MSDASQL.1"); if (false) { // If no Provider keyword is in the string, the OLE DB Provider for // ODBC (MSDASQL) is the default value. This provides backward // compatibility with ODBC connection strings. The ODBC connection // string in the following example can be passed in, and it will // successfully connect. p( "Driver={SQL Server};Server={localhost};Trusted_Connection={yes};" + "db={Northwind};", "Provider", "MSDASQL"); } // Specifying a Keyword // // To identify a keyword used after the Provider keyword, use the // property description of the OLE DB initialization property that you // want to set. For example, the property description of the standard // OLE DB initialization property DBPROP_INIT_LOCATION is // Location. Therefore, to include this property in a connection // string, use the keyword Location. p("Provider='MSDASQL';Location='3Northwind'", "Location", "3Northwind"); // Keywords can contain any printable character except for the equal // sign (=). p( "Jet OLE DB:System Database=c:\\system.mda", "Jet OLE DB:System Database", "c:\\system.mda"); p("Authentication;Info=Column 5", "Authentication;Info", "Column 5"); // If a keyword contains an equal sign (=), it must be preceded by an // additional equal sign to indicate that it is part of the keyword. p("Verification==Security=True", "Verification=Security", "True"); // If multiple equal signs appear, each one must be preceded by an // additional equal sign. p("Many====One=Valid", "Many==One", "Valid"); p("TooMany===False", "TooMany=", "False"); // Setting Values That Use Reserved Characters // // To include values that contain a semicolon, single-quote character, // or double-quote character, the value must be enclosed in double // quotes. p( "ExtendedProperties=\"Integrated Security='SSPI';" + "Initial Catalog='Northwind'\"", "ExtendedProperties", "Integrated Security='SSPI';Initial Catalog='Northwind'"); // If the value contains both a semicolon and a double-quote character, // the value can be enclosed in single quotes. p( "ExtendedProperties='Integrated Security=\"SSPI\";" + "Databse=\"My Northwind DB\"'", "ExtendedProperties", "Integrated Security=\"SSPI\";Databse=\"My Northwind DB\""); // The single quote is also useful if the value begins with a // double-quote character. p("DataSchema='\"MyCustTable\"'", "DataSchema", "\"MyCustTable\""); // Conversely, the double quote can be used if the value begins with a // single quote. p( "DataSchema=\"'MyOtherCustTable'\"", "DataSchema", "'MyOtherCustTable'"); // If the value contains both single-quote and double-quote characters, // the quote character used to enclose the value must be doubled each // time it occurs within the value. p( "NewRecordsCaption='\"Company''s \"new\" customer\"'", "NewRecordsCaption", "\"Company's \"new\" customer\""); p( "NewRecordsCaption=\"\"\"Company's \"\"new\"\" customer\"\"\"", "NewRecordsCaption", "\"Company's \"new\" customer\""); // Setting Values That Use Spaces // // Any leading or trailing spaces around a keyword or value are // ignored. However, spaces within a keyword or value are allowed and // recognized. p("MyKeyword=My Value", "MyKeyword", "My Value"); p("MyKeyword= My Value ;MyNextValue=Value", "MyKeyword", "My Value"); // To include preceding or trailing spaces in the value, the value must // be enclosed in either single quotes or double quotes. p("MyKeyword=' My Value '", "MyKeyword", " My Value "); p("MyKeyword=\" My Value \"", "MyKeyword", " My Value "); if (false) { // (Not supported.) // // If the keyword does not correspond to a standard OLE DB // initialization property (in which case the keyword value is // placed in the Extended Properties (DBPROP_INIT_PROVIDERSTRING) // property), the spaces around the value will be included in the // value even though quote marks are not used. This is to support // backward compatibility for ODBC connection strings. Trailing // spaces after keywords might also be preserved. } if (false) { // (Not supported) // // Returning Multiple Values // // For standard OLE DB initialization properties that can return // multiple values, such as the Mode property, each value returned // is separated with a pipe (|) character. The pipe character can // have spaces around it or not. // // Example Mode=Deny Write|Deny Read } // Listing Keywords Multiple Times // // If a specific keyword in a keyword=value pair occurs multiple times // in a connection string, the last occurrence listed is used in the // value set. p( "Provider='MSDASQL';Location='Northwind';" + "Cache Authentication='True';Prompt='Complete';" + "Location='Customers'", "Location", "Customers"); // One exception to the preceding rule is the Provider keyword. If this // keyword occurs multiple times in the string, the first occurrence is // used. p( "Provider='MSDASQL';Location='Northwind'; Provider='SQLOLEDB'", "Provider", "MSDASQL"); if (false) { // (Not supported) // // Setting the Window Handle Property // // To set the Window Handle (DBPROP_INIT_HWND) property in a // connection string, a long integer value is typically used. } } public void testBufReplace() { // Replace with longer string. Search pattern at beginning & end. checkReplace("xoxox", "x", "yy", "yyoyyoyy"); // Replace with shorter string. checkReplace("xxoxxoxx", "xx", "z", "zozoz"); // Replace with empty string. checkReplace("xxoxxoxx", "xx", "", "oo"); // Replacement string contains search string. (A bad implementation // might loop!) checkReplace("xox", "x", "xx", "xxoxx"); // Replacement string combines with characters in the original to // match search string. checkReplace("cacab", "cab", "bb", "cabb"); // Seek string does not exist. checkReplace( "the quick brown fox", "coyote", "wolf", "the quick brown fox"); // Empty buffer. checkReplace("", "coyote", "wolf", ""); // Empty seek string. This is a bit mean! checkReplace("fox", "", "dog", "dogfdogodogxdog"); } private static void checkReplace( String original, String seek, String replace, String expected) { // Check whether the JDK does what we expect. (If it doesn't it's // probably a bug in the test, not the JDK.) assertEquals(expected, original.replaceAll(seek, replace)); // Check the StringBuffer version of replace. StringBuilder buf = new StringBuilder(original); StringBuilder buf2 = Olap4jUtil.replace(buf, 0, seek, replace); assertTrue(buf == buf2); assertEquals(expected, buf.toString()); // Check the String version of replace. assertEquals(expected, Olap4jUtil.replace(original, seek, replace)); } } // End ConnectStringParserTest.java olap4j-1.0.1.500/testsrc/org/olap4j/impl/Base64Test.java0000644000175000017500000000764711707254766022275 0ustar drazzibdrazzib/* // $Id: Base64Test.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import junit.framework.TestCase; import java.io.*; import java.util.Arrays; import java.util.Random; /** * Test case for {@link Base64}. * * @version $Id: Base64Test.java 482 2012-01-05 23:27:27Z jhyde $ * @author Brian Burton, Julian Hyde */ public class Base64Test extends TestCase { private static final long SEED = 12345678; private static Random s_random = new Random(SEED); private byte[] createData(int length) throws Exception { byte[] bytes = new byte[length]; s_random.nextBytes(bytes); return bytes; } private void runStreamTest(int length) throws Exception { byte[] data = createData(length); ByteArrayOutputStream out_bytes = new ByteArrayOutputStream(); OutputStream out = new Base64.OutputStream(out_bytes); out.write(data); out.close(); byte[] encoded = out_bytes.toByteArray(); byte[] decoded = Base64.decode(encoded, 0, encoded.length); assertTrue(Arrays.equals(data, decoded)); Base64.InputStream in = new Base64.InputStream(new ByteArrayInputStream(encoded)); out_bytes = new ByteArrayOutputStream(); byte[] buffer = new byte[3]; for (int n = in.read(buffer); n > 0; n = in.read(buffer)) { out_bytes.write(buffer, 0, n); } out_bytes.close(); in.close(); decoded = out_bytes.toByteArray(); assertTrue(Arrays.equals(data, decoded)); } public void testStreams() throws Exception { for (int i = 0; i < 100; ++i) { runStreamTest(i); } for (int i = 100; i < 2000; i += 250) { runStreamTest(i); } for (int i = 2000; i < 80000; i += 1000) { runStreamTest(i); } } public void testSimple() { String s = "Man is distinguished, not only by his reason, but by this " + "singular passion from other animals, which is a lust of the " + "mind, that by a perseverance of delight in the continued and " + "indefatigable generation of knowledge, exceeds the short " + "vehemence of any carnal pleasure."; String encoded = Base64.encodeBytes(s.getBytes()); String expected = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\n" + "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\n" + "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\n" + "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\n" + "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="; assertEquals(expected, encoded); byte[] s1 = Base64.decode(encoded); assertEqualsByteArray(s.getBytes(), s1); } private void assertEqualsByteArray(byte[] bytes, byte[] bytes1) { assertEquals(bytes.length, bytes1.length); for (int i = 0; i < bytes.length; i++) { assertEquals(bytes[i], bytes1[i]); } } } // End Base64Test.java olap4j-1.0.1.500/olap4j-1.0.1.500/0000755000175000017500000000000011772422544015240 5ustar drazzibdrazzibolap4j-1.0.1.500/olap4j-1.0.1.500/.classpath0000644000175000017500000000360511656174372017233 0ustar drazzibdrazzib olap4j-1.0.1.500/olap4j-1.0.1.500/.project0000644000175000017500000000057611540136226016707 0ustar drazzibdrazzib OLAP4J org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature olap4j-1.0.1.500/olap4j-1.0.1.500/.settings/0000755000175000017500000000000011421322544017144 5ustar drazzibdrazzibolap4j-1.0.1.500/olap4j-1.0.1.500/.settings/org.eclipse.jdt.core.prefs0000644000175000017500000000061311421322544024126 0ustar drazzibdrazzib#Wed Apr 07 16:39:43 EDT 2010 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.source=1.5 olap4j-1.0.1.500/olap4j-1.0.1.500/.settings/org.eclipse.core.runtime.prefs0000644000175000017500000000011611421322544025026 0ustar drazzibdrazzib#Tue Jul 07 18:46:50 EDT 2009 eclipse.preferences.version=1 line.separator=\n olap4j-1.0.1.500/VERSION.txt0000644000175000017500000000002211713757640014774 0ustar drazzibdrazzibolap4j 1.0.1.500 olap4j-1.0.1.500/checkFile.awk0000644000175000017500000006062511707255014015475 0ustar drazzibdrazzib#!/bin/gawk # $Id: checkFile.awk 484 2012-01-05 23:55:56Z jhyde $ # # Licensed to Julian Hyde under one or more contributor license # agreements. See the NOTICE file distributed with this work for # additional information regarding copyright ownership. # # Julian Hyde licenses this file to you under the Apache License, # Version 2.0 (the "License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== # Checks that a file is valid. # See checkFile.sh. function error(fname, linum, msg) { printf "%s:%d: %s\n", fname, linum, msg; if (0) print; # for debug } function _matchFile(fname) { return fname ~ "/mondrian/" \ || fname ~ "/org/olap4j/" \ || fname ~ "/aspen/" \ || fname ~ "/farrago/" \ || fname ~ "/fennel/" \ || fname ~ "/extensions/" \ || fname ~ "/com/sqlstream/" \ || strict > 0; } function _isCpp(fname) { return fname ~ /\.(cpp|h)$/; } function _isJava(fname) { return fname ~ /\.(java|jj)$/; } function _isMondrian(fname) { return fname ~ /mondrian/; } function push(val) { switchStack[switchStackLen++] = val; } function pop() { --switchStackLen val = switchStack[switchStackLen]; delete switchStack[switchStackLen]; return val; } function afterFile() { # Compute basename. If fname="/foo/bar/baz.txt" then basename="baz.txt". basename = fname; gsub(".*/", "", basename); gsub(lf, "", lastNonEmptyLine); terminator = "// End " basename; if (matchFile && (lastNonEmptyLine != terminator)) { error(fname, FNR, sprintf("Last line should be %c%s%c", 39, terminator, 39)); } } # Returns whether there are unmatched open parentheses. # unmatchedOpenParens("if ()") returns false. # unmatchedOpenParens("if (") returns true. # unmatchedOpenParens("if (foo) bar(") returns false function unmatchedOpenParens(s) { i = index(s, "("); if (i == 0) { if (0) print FNR, "unmatchedOpenParens=0"; return 0; } openCount = 1; while (++i <= length(s)) { c = substr(s, i, 1); if (c == "(") { ++openCount; } if (c == ")") { if (--openCount == 0) { if (0) print FNR, "unmatchedOpenParens=0 (b)"; return 0; } } } if (0) print FNR, "unmatchedOpenParens=1"; return 1; } function countLeadingSpaces(str) { i = 0; while (i < length(str) && substr(str, i + 1, 1) == " ") { ++i; } return i; } function startsWith(s, p) { return length(s) > length(p) \ && substr(s, 1, length(p)) == p; } BEGIN { # pre-compute regexp for quotes, linefeed apos = sprintf("%c", 39); quot = sprintf("%c", 34); lf = sprintf("%c", 13); pattern = apos "(\\" apos "|[^" apos "])" apos; if (0) printf "maxLineLength=%s strict=%s\n", maxLineLength, strict; } FNR == 1 { if (fname) { afterFile(); } fname = FILENAME; matchFile = _matchFile(fname); isCpp = _isCpp(fname); isJava = _isJava(fname); mondrian = _isMondrian(fname); prevImport = ""; prevImportGroup = ""; } { if (previousLineEndedInCloseBrace > 0) { --previousLineEndedInCloseBrace; } if (previousLineEndedInOpenBrace > 0) { --previousLineEndedInOpenBrace; } if (previousLineWasEmpty > 0) { --previousLineWasEmpty; } s = $0; # remove DOS linefeeds gsub(lf, "", s); # replace strings gsub(/"(\\"|[^"\\]|\\[^"])*"/, "string", s); # replace single-quoted strings gsub(pattern, "string", s); # replace {: and :} in .cup files if (fname ~ /\.cup$/) { gsub(/{:/, "{", s); gsub(/:}/, "}", s); gsub(/:/, " : ", s); } if (inComment && $0 ~ /\*\//) { # end of multiline comment "*/" inComment = 0; gsub(/^.*\*\//, "/* comment */", s); } else if (inComment) { s = "/* comment */"; } else if ($0 ~ /\/\*/ && $0 !~ /\/\*.*\*\//) { # beginning of multiline comment "/*" inComment = 1; gsub(/\/\*.*$/, "/* comment */", s); } else { # mask out /* */ comments gsub(/\/\*.*\*\//, "/* comment */", s); } if (mondrian && s ~ /\/\/\$NON-NLS/) { error(fname, FNR, "NON-NLS not allowed"); } # mask out // comments gsub(/\/\/.*$/, "// comment", s); # line starts with string or plus? if (s ~ /^ *string/ \ && s !~ /)/) { stringCol = index(s, "string"); } else if (s ~ /^ *[+] string/) { if (stringCol != 0 && index(s, "+") != stringCol) { error(fname, FNR, "String '+' must be aligned with string on line above"); } } else if (s ~ /comment/) { # in comment; string target carries forward } else { stringCol = 0; } # Is the line indented as expected? if (nextIndent > 0) { indent = countLeadingSpaces(s); if (indent != nextIndent) { error(fname, FNR, "Incorrect indent for first line of arg list"); } } nextIndent = -1; } / $/ { error(fname, FNR, "Line ends in space"); } /[\t]/ { if (matchFile) { error(fname, FNR, "Tab character"); } } /[\r]/ { if (matchFile) { error(fname, FNR, "Carriage return character (file is in DOS format?)"); } } /./ { lastNonEmptyLine = $0; } { # Rules beyond this point only apply to Java and C++. if (!isCpp && !isJava) { next; } } /^package / { thisPackage = $2; } /^package / && previousLineWasEmpty { error(fname, FNR, "'package' declaration must not occur after empty line"); } /^import / { if (previousLineWasEmpty) { prevImport = ""; } else { if (!prevImport) { error(fname, FNR, "Expected blank line before first import"); } } thisImport = $2; gsub(/;/, "", thisImport); gsub(/\*/, "", thisImport); if (thisPackage ~ /^mondrian.*/ && thisImport ~ /^mondrian.*/ \ || thisPackage ~ /^org.olap4j.*/ && thisImport ~ /^org.olap4j.*/) { importGroup = "a"; } else if (thisImport ~ /^static/) { importGroup = "z"; } else if (thisImport ~ /^java.*/) { importGroup = "y"; } else if (thisImport ~ /^junit.*/) { importGroup = "b"; } else if (thisImport ~ /^mondrian.*/) { importGroup = "bb"; } else if (thisImport ~ /^org.apache.*/) { importGroup = "c"; } else if (thisImport ~ /^org.eigenbase.*/) { importGroup = "d"; } else if (thisImport ~ /^org.olap4j.*/) { importGroup = "e"; } else { importGroup = "f"; } if (importGroup != prevImportGroup \ && prevImportGroup) { if (!previousLineWasEmpty) { error(fname, FNR, "Expected blank line between import groups"); } else if (prevImportGroup > importGroup) { error(fname, FNR, "Import group out of sequence (should precede " prevImportGroup ")"); } } else if (prevImport \ && prevImport > thisImport \ && !startsWith(prevImport, thisImport) \ && !startsWith(thisImport, prevImport)) { error(fname, FNR, "Import out of sorted order"); } prevImport = thisImport; prevImportGroup = importGroup; } /^\/\/ Copyright .* Julian/ && strict { if ($0 !~ /-2012/) { error(fname, FNR, "copyright is not current"); } } /(static|public|private|protected|final|abstract)/ && !/import/ && strict > 1 { # Order of qualifiers: "public/private/protected static final abstract class ..." s2 = s; gsub(/\(.*$/, "", s2); if (s2 ~ /abstract .*final/) { error(fname, FNR, "'final' must come before 'abstract'"); } if (s2 ~ /final .*static/) { error(fname, FNR, "'static' must come before 'final'"); } if (s2 ~ /abstract .*static/) { error(fname, FNR, "'static' must come before 'abstract'"); } if (s2 ~ /static .*(public|protected|private)/) { error(fname, FNR, "'public/private/protected' must come before 'static'"); } if (s2 ~ /final .*(public|protected|private)/) { error(fname, FNR, "'public/private/protected' must come before 'final'"); } if (s2 ~ /abstract .*(public|protected|private)/) { error(fname, FNR, "'public/private/protected' must come before 'abstract'"); } } /^$/ { if (matchFile && previousLineEndedInOpenBrace) { error(fname, FNR, "Empty line following open brace"); } } /^ +}( catch| finally| while|[;,)])/ || /^ +}$/ { if (matchFile && previousLineWasEmpty) { error(fname, FNR - 1, "Empty line before close brace"); } } s ~ /\.*;$/ { if (!matchFile) {} else { error(fname, FNR, "if followed by statement on same line"); } } s ~ /\<(if) *\(/ { if (!matchFile) { } else if (s !~ /\<(if) /) { error(fname, FNR, "if must be followed by space"); } else if (s ~ / else if /) { } else if (s ~ /^#if /) { } else if (s !~ /^( )*(if)/) { error(fname, FNR, "if must be correctly indented"); } } s ~ /\<(while) *\(/ { if (!matchFile) { } else if (s !~ /\<(while) /) { error(fname, FNR, "while must be followed by space"); } else if (s ~ /} while /) { } else if (s !~ /^( )+(while)/) { error(fname, FNR, "while must be correctly indented"); } } s ~ /\<(for|switch|synchronized|} catch) *\(/ { if (!matchFile) {} else if (s !~ /^( )*(for|switch|synchronized|} catch)/) { error(fname, FNR, "for/switch/synchronized/catch must be correctly indented"); } else if (s !~ /\<(for|switch|synchronized|} catch) /) { error(fname, FNR, "for/switch/synchronized/catch must be followed by space"); } } s ~ /\<(if|while|for|switch|catch)\>/ { # Check single-line if statements, such as # if (condition) return; # We recognize such statements because there are equal numbers of open and # close parentheses. opens = s; gsub(/[^(]/, "", opens); closes = s; gsub(/[^)]/, "", closes); if (!matchFile) { } else if (s ~ /{( *\/\/ comment)?$/) { # lines which end with { and optional comment are ok } else if (s ~ /{.*\\$/ && isCpp) { # lines which end with backslash are ok in c++ macros } else if (s ~ /} while/) { # lines like "} while (foo);" are ok } else if (s ~ /^#/) { # lines like "#if 0" are ok } else if (s ~ /if \(true|false\)/) { # allow "if (true)" and "if (false)" because they are # used for commenting } else if (!unmatchedOpenParens(s) \ && length($0) != 79 \ && length($0) != 80) { error(fname, FNR, "single-line if/while/for/switch/catch must end in {"); } } s ~ /[[:alnum:]]\(/ && s !~ /\<(if|while|for|switch|assert)\>/ { ss = s; while (match(ss, /[[:alnum:]]\(/)) { ss = substr(ss, RSTART + RLENGTH - 1); parens = ss; gsub(/[^()]/, "", parens); while (substr(parens, 1, 2) == "()") { parens = substr(parens, 3); } opens = parens; gsub(/[^(]/, "", opens); closes = parens; gsub(/[^)]/, "", closes); if (length(opens) > length(closes)) { if (ss ~ /,$/) { bras = ss; gsub(/[^<]/, "", bras); kets = ss; gsub(/->/, "", kets); gsub(/[^>]/, "", kets); if (length(bras) > length(kets)) { # Ignore case like 'for (Map.Entry entry : ...' } else if (s ~ / for /) { # Ignore case like 'for (int i = 1,{nl} j = 2; i < j; ...' } else { error( \ fname, FNR, \ "multi-line parameter list should start with newline"); break; } } else if (s ~ /[;(]( *\\)?$/) { # If open paren is at end of line (with optional backslash # for macros), we're fine. } else if (s ~ /@.*\({/) { # Ignore Java annotations. } else { error( \ fname, FNR, \ "Open parenthesis should be at end of line (function call spans several lines)"); break; } } ss = substr(ss, 2); # remove initial "(" } } s ~ /\/ { push(switchCol); switchCol = index($0, "switch"); } s ~ /{/ { braceCol = index($0, "{"); if (braceCol == switchCol) { push(switchCol); } } s ~ /}/ { braceCol = index($0, "}"); if (braceCol == switchCol) { switchCol = pop(); } } s ~ /\<(case|default)\>/ { caseDefaultCol = match($0, /case|default/); if (!matchFile) {} else if (caseDefaultCol != switchCol) { error(fname, FNR, "case/default must be aligned with switch"); } } s ~ /\/ { if (!matchFile) {} else if (isCpp) {} # rule only applies to java else if (s !~ /^( )+(assert)/) { error(fname, FNR, "assert must be correctly indented"); } else if (s !~ /\/ { if (!matchFile) {} else if (isCpp && s ~ /^#/) { # ignore macros } else if (s !~ /^( )+(return)/) { error(fname, FNR, "return must be correctly indented"); } else if (s !~ /\/ { if (!matchFile) {} else if (isCpp) { # cannot yet handle C++ cases like 'void foo() throw(int)' } else if (s !~ /^( )+(throw)/) { error(fname, FNR, "throw must be correctly indented"); } else if (s !~ /\/ { if (!matchFile) {} else if (isCpp && s ~ /^# *else$/) {} # ignore "#else" else if (s !~ /^( )+} else (if |{$|{ *\/\/|{ *\/\*)/) { error(fname, FNR, "else must be preceded by } and followed by { or if and correctly indented"); } } s ~ /\/ { if (!matchFile) {} else if (s !~ /^( )*do {/) { error(fname, FNR, "do must be followed by space {, and correctly indented"); } } s ~ /\/ { if (!matchFile) {} else if (s !~ /^( )+try {/) { error(fname, FNR, "try must be followed by space {, and correctly indented"); } } s ~ /\/ { if (!matchFile) {} else if (s !~ /^( )+} catch /) { error(fname, FNR, "catch must be preceded by }, followed by space, and correctly indented"); } } s ~ /\/ { if (!matchFile) {} else if (s !~ /^( )+} finally {/) { error(fname, FNR, "finally must be preceded by }, followed by space {, and correctly indented"); } } s ~ /\($/ { nextIndent = countLeadingSpaces(s) + 4; if (s ~ / (if|while) .*\(.*\(/) { nextIndent += 4; } } match(s, /([]A-Za-z0-9()])(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:) *[A-Za-z0-9(]/, a) { # < and > are not handled here - they have special treatment below if (!matchFile) {} # else if (s ~ /<.*>/) {} # ignore templates else if (a[2] == "-" && s ~ /\(-/) {} # ignore case "foo(-1)" else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5 else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5 else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:" else if (isCpp && s ~ /[^ ][*&]/) {} # ignore e.g. "Foo* p;" in c++ - debatable else if (isCpp && s ~ /\" in c++ else { error(fname, FNR, "operator '" a[2] "' must be preceded by space"); } } match(s, /([]A-Za-z0-9() ] *)(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:|,)[A-Za-z0-9(]/, a) { if (!matchFile) {} # else if (s ~ /<.*>/) {} # ignore templates else if (a[2] == "-" && s ~ /(\(|return |case |= )-/) {} # ignore prefix - else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:" else if (s ~ /, *-/) {} # ignore case "foo(x, -1)" else if (s ~ /-[^ ]/ && s ~ /[^A-Za-z0-9] -/) {} # ignore case "x + -1" but not "x -1" or "3 -1" else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5 else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5 else if (a[2] == "*" && isCpp && s ~ /\*[^ ]/) {} # ignore e.g. "Foo *p;" in c++ else if (a[2] == "&" && isCpp && s ~ /&[^ ]/) {} # ignore case "foo(&x)" in c++ else if (isCpp && s ~ /\" in c++ else if (strict < 2 && fname ~ /(fennel)/ && a[1] = ",") {} # not enabled yet else { error(fname, FNR, "operator '" a[2] "' must be followed by space"); } } match(s, /( )(,)/, a) { # (, < and > are not handled here - they have special treatment below if (!matchFile) {} else { error(fname, FNR, "operator '" a[2] "' must not be preceded by space"); } } match(s, / (+|-|\*|\/|==|>=|<=|!=|<<|<<<|>>|&|&&|\|\||\?|:)$/, a) || \ match(s, /(\.|->)$/, a) { if (strict < 2 && fname ~ /(aspen)/ && a[1] != ":") {} # not enabled yet else if (strict < 2 && fname ~ /(fennel|farrago|aspen)/ && a[1] = "+") {} # not enabled yet else if (a[1] == ":" && s ~ /(case.*|default):$/) { # ignore e.g. "case 5:" } else if ((a[1] == "*" || a[1] == "&") && isCpp && s ~ /^[[:alnum:]:_ ]* [*&]$/) { # ignore e.g. "const int *\nClass::Subclass2::method(int x)" } else { error(fname, FNR, "operator '" a[1] "' must not be at end of line"); } } match(s, /^ *(=) /, a) { error(fname, FNR, "operator '" a[1] "' must not be at start of line"); } match(s, /([[:alnum:]~]+)( )([(])/, a) { # (, < and > are not handled here - they have special treatment below if (!matchFile) {} else if (isJava && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|synchronized|assert)\>/) {} else if (isCpp && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|operator|void|PBuffer)\>/) {} else if (isCpp && s ~ /^#define /) {} else { error(fname, FNR, "there must be no space before '" a[3] "' in fun call or fun decl"); } } s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*' could be a template else { error(fname, FNR, "operator '<' must be preceded by space"); } } s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*>/ { # E.g. "g>" but not "String>" as in "List" if (!matchFile) {} else if (isCpp) {} # in C++ 'xyz' could be a template else { error(fname, FNR, "operator '>' must be preceded by space"); } } match(s, /<([[:digit:][:lower:]][[:alnum:].]*)\>/, a) { if (!matchFile) {} else if (isCpp) { # in C++, template and include generate too many false positives } else if (isJava && a[1] ~ /(int|char|long|boolean|byte|double|float)/) { # Allow e.g. 'List' } else if (isJava && a[1] ~ /^[[:lower:]]+\./) { # Allow e.g. 'List' } else { error(fname, FNR, "operator '<' must be followed by space"); } } match(s, /^(.*[^-])>([[:digit:][:lower:]][[:alnum:]]*)\>/, a) { if (!matchFile) {} else if (isJava && a[1] ~ /.*\.<.*/) { # Ignore 'Collections.member' } else { error(fname, FNR, "operator '>' must be followed by space"); } } s ~ /[[(] / { if (!matchFile) {} else if (s ~ /[[(] +\\$/) {} # ignore '#define foo( \' else { error(fname, FNR, "( or [ must not be followed by space"); } } s ~ / [])]/ { if (!matchFile) {} else if (s ~ /^ *\)/ && previousLineEndedInCloseBrace) {} # ignore "bar(new Foo() { } );" else { error(fname, FNR, ") or ] must not be followed by space"); } } s ~ /}/ { if (!matchFile) {} else if (s !~ /}( |;|,|$|\))/) { error(fname, FNR, "} must be followed by space"); } else if (s !~ /( )*}/) { error(fname, FNR, "} must be at start of line and correctly indented"); } } s ~ /{/ { if (!matchFile) {} else if (s ~ /(\]\)?|=) *{/) {} # ignore e.g. "(int[]) {1, 2}" or "int[] x = {1, 2}" else if (s ~ /\({/) {} # ignore e.g. @SuppressWarnings({"unchecked"}) else if (s ~ /{ *(\/\/|\/\*)/) {} # ignore e.g. "do { // a comment" else if (s ~ / \{\}$/) {} # ignore e.g. "Constructor() {}" else if (s ~ / },$/) {} # ignore e.g. "{ yada }," else if (s ~ / };$/) {} # ignore e.g. "{ yada };" else if (s ~ / \{\};$/) {} # ignore e.g. "template <> class Foo {};" else if (s ~ / },? *\/\/.*$/) {} # ignore e.g. "{ yada }, // comment" else if (s ~ /\\$/) {} # ignore multiline macros else if (s ~ /{}/) { # e.g. "Constructor(){}" error(fname, FNR, "{} must be preceded by space and at end of line"); } else if (isCpp && s ~ /{ *\\$/) { # ignore - "{" can be followed by "\" in c macro } else if (s !~ /{$/) { error(fname, FNR, "{ must be at end of line"); } else if (s !~ /(^| ){/) { error(fname, FNR, "{ must be preceded by space or at start of line"); } else { opens = s; gsub(/[^(]/, "", opens); closes = s; gsub(/[^)]/, "", closes); if (0 && strict < 2 && fname ~ /aspen/) {} # not enabled else if (length(closes) > length(opens)) { error(fname, FNR, "Open brace should be on new line (function call/decl spans several lines)"); } } } s ~ /(^| )(class|interface|enum) / || s ~ /(^| )namespace / && isCpp { if (isCpp && s ~ /;$/) {} # ignore type declaration else { classDeclStartLine = FNR; t = s; gsub(/.*(class|interface|enum|namespace) /, "", t); gsub(/ .*$/, "", t); if (s ~ /template/) { # ignore case "template static void foo()" classDeclStartLine = 0; } else if (t ~ /[[:upper:]][[:upper:]][[:upper:]][[:upper:]]/ \ && t !~ /LRU/ \ && t !~ /WAL/ \ && t !~ /classUUID/ \ && t !~ /classSQLException/ \ && t !~ /BBRC/ \ && t !~ /_/ \ && t !~ /EncodedSqlInterval/) { error(fname, FNR, "Class name " t " has consecutive uppercase letters"); } } } s ~ / throws\>/ { if (s ~ /\(/) { funDeclStartLine = FNR; } else { funDeclStartLine = FNR - 1; } } length($0) > maxLineLength \ && $0 !~ /@(throws|see|link)/ \ && $0 !~ /\$Id: / \ && $0 !~ /^import / \ && $0 !~ /http:/ \ && $0 !~ /\/\/ Expect "/ \ && s !~ /^ *(\+ |<< )?string\)?[;,]?$/ { error( \ fname, \ FNR, \ "Line length (" length($0) ") exceeds " maxLineLength " chars"); } /}$/ { previousLineEndedInCloseBrace = 2; } /;$/ { funDeclStartLine = 0; } /{$/ { # Ignore open brace if it is part of class or interface declaration. if (classDeclStartLine) { if (classDeclStartLine < FNR \ && $0 !~ /^ *{$/) { error(fname, FNR, "Open brace should be on new line (class decl spans several lines)"); } classDeclStartLine = 0; } else { previousLineEndedInOpenBrace = 2; } if (funDeclStartLine) { if (funDeclStartLine < FNR \ && $0 !~ /^ *{$/) { if (strict < 2 && fname ~ /aspen/) {} # not enabled else error(fname, FNR, "Open brace should be on new line (function decl spans several lines)"); } funDeclStartLine = 0; } } /^$/ { previousLineWasEmpty = 2; } { next; } END { afterFile(); } # End checkFile.awk olap4j-1.0.1.500/simple-jndi/0000755000175000017500000000000011504374312015314 5ustar drazzibdrazzibolap4j-1.0.1.500/simple-jndi/jdbc.properties0000644000175000017500000000046611633616254020351 0ustar drazzibdrazzibSampleData/type=javax.sql.DataSource SampleData/driver=com.mysql.jdbc.Driver #SampleData/url=jdbc:hsqldb:file:foodmart/foodmart SampleData/url=jdbc:mysql://localhost/foodmart?user=foodmart&password=foodmart #SampleData/url=jdbc:hsqldb:mem:olap4j-test SampleData/user=foodmart SampleData/password=foodmartolap4j-1.0.1.500/LICENSE0000644000175000017500000002613611707254766014135 0ustar drazzibdrazzib Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. olap4j-1.0.1.500/build.xml0000644000175000017500000006030311707526414014733 0ustar drazzibdrazzib /* * Project version information. Generated - do not modify. */ package org.olap4j.driver.xmla; /** * Version information for the XMLA driver. (Generated.) */ class XmlaOlap4jDriverVersion { static final String NAME = "olap4j driver for XML/A"; static final String VERSION = "${project.revision}"; static final int MAJOR_VERSION = Integer.valueOf("${project.revision.major}"); static final int MINOR_VERSION = Integer.valueOf("${project.revision.minor}"); } // End XmlaOlap4jDriverVersion.java olap4j-1.0.1.500/test.properties0000644000175000017500000001014511707522202016175 0ustar drazzibdrazzib# # $Id: test.properties 483 2012-01-05 23:43:18Z jhyde $ # # Licensed to Julian Hyde under one or more contributor license # agreements. See the NOTICE file distributed with this work for # additional information regarding copyright ownership. # # Julian Hyde licenses this file to you under the Apache License, # Version 2.0 (the "License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################### # This is the default repo file to allow CI builds to function properly. # Please do not commit any changes on it. # # # SPECIAL NOTE. # If the TCK is launched within Ant, the default amount of memory that # is allowed for Ant won't do the job. There are lots of OLAP operations # to perform and it is strongly suggested to give at lease 1 gig of ram # to Ant in order to run properly. You can easily achieve this by setting # ANT_OPTS environment variable to "-Xmx1024m". ############################################################################### ############################################################################### # This activates the Mondrian in-process tester. # It is the default in-process Mondrian tester. # By default, it will use a file based HSQLDB in the # /foodmart folder. If you want to test olap4j against # a different database, edit the jdbc.properties file # in the /simple-jndi folder. #org.olap4j.test.helperClassName=mondrian.test.MondrianOlap4jTester org.olap4j.test.connectUrl=jdbc:mondrian:Datasource=jdbc/SampleData;Catalog=./foodmart/FoodMart.xml; ############################################################################### # These two lines activate the XMLA tester. Uncomment the two # lines below to activate it. Make sure you comment out all others. # The in-process XML/A tester is a memory hog. Read the comment above. # By default, it will use a file based HSQLDB in the # /foodmart folder. If you want to test olap4j against # a different database, edit the jdbc.properties file # in the /simple-jndi folder. org.olap4j.test.helperClassName=org.olap4j.XmlaTester org.olap4j.XmlaTester.CatalogUrl=file:foodmart/FoodMart.xml ############################################################################### # These options are used to test against a remote XML/A server. # Uncomment those properties and comment out the others above to # activate it. The server must have the FoodMart schema installed. # Both the data and the schema can be found in /foodmart #org.olap4j.test.helperClassName=org.olap4j.RemoteXmlaTester #org.olap4j.RemoteXmlaTester.JdbcUrl=jdbc:xmla:Server=http://localhost:81/mondrian/xmla #org.olap4j.RemoteXmlaTester.Username=joe #org.olap4j.RemoteXmlaTester.Password=password ############################################################################### # Examples of the remote XMLA tester using a special proxy to record/play # known responses. So far, it is only a proof of concept. We do not recommend # to rely on this for testing. # This example uses a cached Mondrian 3.3-SNAPSHOT server requests/responses # hsqldb database to run the TCK. # To make this example work, one must first unzip the data file manually. #org.olap4j.test.helperClassName=org.olap4j.RemoteXmlaTester #org.olap4j.RemoteXmlaTester.JdbcUrl=jdbc:xmla:Server=http://localhost:81/mondrian/xmla;Cache=org.olap4j.driver.xmla.cache.XmlaDatabaseCache;Cache.Play=true # This other example connects to an olap server and records the requests to # an hsqldb database that it creates. #org.olap4j.test.helperClassName=org.olap4j.RemoteXmlaTester #org.olap4j.RemoteXmlaTester.JdbcUrl=jdbc:xmla:Server=http://localhost:81/mondrian/xmla;Cache=org.olap4j.driver.xmla.cache.XmlaDatabaseCache;Cache.Init=true;Cache.Record=true # End test.properties olap4j-1.0.1.500/ivy.xml0000644000175000017500000000467611707255014014451 0ustar drazzibdrazzib olap4j is an open Java API for OLAP. Think of it like JDBC, but 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. olap4j-1.0.1.500/foodmart/0000755000175000017500000000000011713757656014736 5ustar drazzibdrazzibolap4j-1.0.1.500/README.txt0000644000175000017500000001302711714242460014603 0ustar drazzibdrazzib# $Id: README.txt 503 2012-02-07 21:35:50Z lucboudreau $ olap4j, release 1.0.1 Contents of this distribution ----------------------------- This is a distribution of olap4j, the open Java API for accessing OLAP data. For version information, see VERSION.txt. For licensing, see LICENSE/NOTICE. For details regarding this release and the changes it introduces, see CHANGES.txt. Olap4j is distributed as four Java JAR libraries. * olap4j-[version].jar Core API, Query Model, Transformation and other auxiliary packages, along with the driver specification. * olap4j-xmla-[version].jar Driver implementation of olap4j for XML/A data sources. It is compatible with Mondrian, Palo, SAP BW and SQL Server 2005+. * olap4j-tck-[version].jar Technology compatibility kit. Consists mostly of JUnit tests. * olap4j-jdk14-[version].jar Olap4j distribution compatible with Java 1.4. Includes the core API and the XML/A driver. Packages and Roadmap ----------------------------- The core API of olap4j version 1.0 is a Long Term Support (LTS) release, but some parts of the olap4j project will remain considered as experimental, thus subject to change in future releases. Core packages ----------------------------- The core packages in olap4j-1.0 are as follows. * org.olap4j.driver.xmla Generic XML/A driver. * org.olap4j.mdx Core objects of the MDX model. * org.olap4j.mdx.parser Parser for the MDX query language. * org.olap4j.metadata Discovery of OLAP servers metadata. * org.olap4j.type System for the core MDX object model and the metadata package. Experimental packages ----------------------------- The following packages are considered experimental and are subject to change. * org.olap4j.query Programmatic Query Model. * org.olap4j.transform Core MDX object model transformation utilities. * org.olap4j.layout Utility classes to display CellSets. * org.olap4j.CellSetListener and all associated classes Event-based system for real time updates of CellSet objects. * org.olap4j.Scenario and all associated classes Statistical simulations module. Dependencies ----------------------------- olap4j requires the following libraries at run time: * lib/olap4j.jar (or lib/olap4j-jdk14.jar if you are running JDK 1.4) * lib/javacup.jar If you use the JDK 1.4 compatible jar, you will also need: * lib/retroweaver.jar * lib/retroweaver-rt.jar * lib/asm.jar * lib/asm-commons.jar If you are using the XML/A driver, you will also need: * lib/xercesImpl.jar The TCK requires: * lib/commons-dbcp.jar Building olap4j from source --------------------------- 1. Unzip olap4j--src.zip. 2. Update buildOnJdk.[sh|bat]. If you are building on a Linux/Unix/Whatever machine, you only need to create symlinks to /usr/lib/jvm/${jdkVersion} where jdkVersion is one of 1.5, 1.6 or 1.7. If you are building on a Windows system, including Cygwin users, edit the Batch file and set the properties JAVA_HOME_1* to the paths of the corresponding JVM installation paths. You can also set these variables in your system environment. 3. Run a test build: $ ant clean-all dist Writing a simple program ------------------------ You can now write and run a simple program against olap4j. For example, under Java 6, import org.olap4j.*; import org.olap4j.metadata.Member; import java.sql.*; Class.forName("org.olap4j.driver.xmla.XmlaOlap4jDriver"); Connection connection = DriverManager.getConnection( "jdbc:xmla:" + "Server=http://example.com:8080/mondrian/xmla"); OlapConnection olapConnection = connection.unwrap(OlapConnection.class); OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery( "SELECT {[Measures].[Unit Sales]} ON 0,\n" + "{[Product].Children} ON 1\n" + "FROM [Sales]"); for (Position row : cellSet.getAxes().get(1)) { for (Position column : cellSet.getAxes().get(0)) { for (Member member : row.getMembers()) { System.out.println(member.getUniqueName()); } for (Member member : column.getMembers()) { System.out.println(member.getUniqueName()); } final Cell cell = cellSet.getCell(column, row); System.out.println(cell.getFormattedValue()); System.out.println(); } } Or, if you are using the in-process mondrian driver, include mondrian.jar and its dependencies in your classpath, and change the appropriate lines in the above code to the following: Class.forName("mondrian.olap4j.MondrianOlap4jDriver"); Connection connection = DriverManager.getConnection( "jdbc:mondrian:" + "Jdbc='jdbc:odbc:MondrianFoodMart';" + "Catalog='file://c:/open/mondrian/demo/FoodMart.xml';" + "JdbcDrivers=sun.jdbc.odbc.JdbcOdbcDriver;"); JDK 1.4 ------- This distribution includes a JDK 1.4-compatible library for olap4j. If you are using JDK version 1.4, replace olap4j.jar in your classpath with olap4j-jdk14.jar. # End README.txt olap4j-1.0.1.500/NOTICE0000644000175000017500000000150111707254766014021 0ustar drazzibdrazzibolap4j Copyright (C) 2005-2012, Julian Hyde This product includes software developed by Julian Hyde (http://www.hydromatic.net). Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. subfloor.xml was developed by Pentaho Corporation (http://www.pentaho.com). Portions of this product were derived from the Mondrian OLAP Engine (http://mondrian.pentaho.org). olap4j-1.0.1.500/buildOnJdk.bat0000644000175000017500000000511711707254764015637 0ustar drazzibdrazzib@echo off rem $Id: buildOnJdk.bat 484 2012-01-05 23:55:56Z jhyde $ rem rem Licensed to Julian Hyde under one or more contributor license rem agreements. See the NOTICE file distributed with this work for rem additional information regarding copyright ownership. rem rem Julian Hyde licenses this file to you under the Apache License, rem Version 2.0 (the "License"); you may not use this file except in rem compliance with the License. You may obtain a copy of the License at: rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. rem **** This program takes 1 argument and a series of other arguments to pass to Ant. rem **** - buildOnJdk.bat [jdk version] [ant arguments] rem **** The value of [jdk version] must be one of: rem **** - jdk1.5 rem **** - jdk1.6 rem **** - jdk1.7 rem **** It assumes the following environment variables are set. rem **** - JAVA_HOME_15: Home directory of a JDK 1.5.X. rem **** - JAVA_HOME_16: Home directory of a JDK 1.6.X. rem **** - JAVA_HOME_17: Home directory of a JDK 1.7.X. rem **** It also assumes that Ant is on the classpath. rem ============================================================================= rem ===== You can set some environment variables right here if needed =========== rem Change the following line to point to your JDK 1.5 home. set JAVA_HOME_15=C:\apps\java\jdk1.5.0_22 rem Change the following line to point to your JDK 1.6 home. set JAVA_HOME_16=C:\apps\java\jdk1.6.0_27 rem Change the following line to point to your JDK 1.7 home. set JAVA_HOME_17=C:\apps\java\jdk1.7.0_01 rem Change the following line to point to your ant home. rem set ANT_HOME=C:\apps\ant\1.7.1 rem set ANT_HOME=C:\apps\ant\1.8.1 rem ====================================================== rem ===== Don't touch anything below this line =========== if %1==jdk1.5 ( set JAVA_HOME=%JAVA_HOME_15% ) if %1==jdk1.6 ( set JAVA_HOME=%JAVA_HOME_16% ) if %1==jdk1.7 ( set JAVA_HOME=%JAVA_HOME_17% ) set ANT_ARGUMENTS= for %%A in (%*) do ( set ANT_ARGUMENTS=%ANT_ARGUMENTS% %%A ) rem We set JAVACMD for the benefit of Ant. set JAVACMD=%JAVA_HOME%\bin\java.exe rem Some debug info echo Using ANT_HOME: %ANT_HOME% echo Using JAVA_HOME: %JAVA_HOME% echo Using JAVACMD: %JAVACMD% echo Using Ant arguments: %ANT_ARGUMENTS% ant %ANT_ARGUMENTS% rem End buildJdk16.bat olap4j-1.0.1.500/ivysettings.xml0000644000175000017500000000220511421322544016210 0ustar drazzibdrazzib olap4j-1.0.1.500/ivy-xmla.xml0000644000175000017500000000412711707255014015377 0ustar drazzibdrazzib XML/A driver for olap4j. olap4j-1.0.1.500/buildOnJdk.sh0000644000175000017500000000275211707254766015507 0ustar drazzibdrazzib# # $Id: buildOnJdk.sh 484 2012-01-05 23:55:56Z jhyde $ # # Licensed to Julian Hyde under one or more contributor license # agreements. See the NOTICE file distributed with this work for # additional information regarding copyright ownership. # # Julian Hyde licenses this file to you under the Apache License, # Version 2.0 (the "License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # ============================================================================== # Called recursively from 'ant release' to build the files which can only be # built under a particular JDK version. # # Usage: # buildOnJdk.sh # # For example: # buildOnJdk.sh jdk1.6 compile.java jdkVersion=$1 shift # Change the following line to point each JDK's home. case "$jdkVersion" in (*) export JAVA_HOME=/usr/lib/jvm/${jdkVersion};; esac if [ ! -d "$JAVA_HOME" ]; then echo "$0: Invalid JAVA_HOME $JAVA_HOME; skipping compile." exit 1 fi export PATH=$JAVA_HOME/bin:$PATH echo Using JAVA_HOME: $JAVA_HOME echo Using Ant arguments: $@ ant "$@" # End buildOnJdk.sh olap4j-1.0.1.500/build.properties0000644000175000017500000000340011713757072016325 0ustar drazzibdrazzib# # $Id: build.properties 495 2012-01-24 20:05:49Z lucboudreau $ # # Licensed to Julian Hyde under one or more contributor license # agreements. See the NOTICE file distributed with this work for # additional information regarding copyright ownership. # # Julian Hyde licenses this file to you under the Apache License, # Version 2.0 (the "License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Modify this file to override build settings. It is read by ant's build.xml. # See also 'test.properties', which contains settings for the regression # suite. # Uncomment one of the following 2 lines. (We use -SNAPSHOT during development, # so that projects such as mondrian can run on the very latest; we switch for a # specific revision number near to a release. Change 'xxx' the latest subversion # change number; and put the same number in 'project.revision.minor'.) project.revision=1.0.1.500 #project.revision=1.0.0.xxx project.revision.major=1 project.revision.minor=00010500 ivy.artifact.id=olap4j ivy.artifact.group=org.olap4j impl.title=olap4j javadoc.packagenames=org.olap4j.* build.dir=build ivy.repository.publish=http://repo.pentaho.org/artifactory # Uncomment to use yDoc doclet for enhanced javadoc (requires commercial # license). #ydoc.home=/usr/local/ydoc-3.0-jdk1.5 # End build.properties olap4j-1.0.1.500/checkFile.sh0000644000175000017500000002035011707255014015314 0ustar drazzibdrazzib#!/bin/bash # $Id: checkFile.sh 484 2012-01-05 23:55:56Z jhyde $ # # Licensed to Julian Hyde under one or more contributor license # agreements. See the NOTICE file distributed with this work for # additional information regarding copyright ownership. # # Julian Hyde licenses this file to you under the Apache License, # Version 2.0 (the "License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # ============================================================================== # Checks that a file is valid. # The file is deemed to be valid if this command produces no output. # # Usage: # checkFile [ --depotPath ] # usage() { echo "checkFile [ ] --depotPath " echo " Checks a temporary file. depotPath is the full path of" echo " the file stored in perforce, for error reporting; file" echo " holds the actual file contents." echo "checkFile [ ] ..." echo " Checks a list of files." echo "checkFile [ ] --opened" echo " Checks all files that are opened for edit in the current" echo " perforce client." echo "checkFile [ ] --under

" echo " Recursively checks all files under a given directory." echo "checkFile --help" echo " Prints this help." echo echo "Options:" echo "--lenient" echo " Does not apply rules to components which are not known to" echo " be in compliance. The perforce trigger uses this option." echo "--strict" echo " Stricter than usual; the opposite of lenient." } doCheck() { filePath="$1" file="$2" maxLineLength="$3" # CHECKFILE_IGNORE is an environment variable that contains a callback # to decide whether to check this file. The command or function should # succeed (that is, return 0) if checkFile is to ignore the file, fail # (that is, return 1 or other non-zero value) otherwise. if [ "$CHECKFILE_IGNORE" ]; then if eval $CHECKFILE_IGNORE "$filePath"; then return fi fi # Exceptions for mondrian case "$filePath" in */mondrian/util/Base64.java| \ */mondrian/olap/MondrianDef.java| \ */mondrian/gui/MondrianGuiDef.java| \ */mondrian/xmla/DataSourcesConfig.java| \ */mondrian/rolap/aggmatcher/DefaultDef.java| \ */mondrian/resource/MondrianResource*.java| \ */mondrian/olap/Parser.java| \ */mondrian/olap/ParserSym.java) # mondrian.util.Base64 is checked in as is, so don't check it # Other files above are generated. return ;; # Exceptions for olap4j */org/olap4j/mdx/parser/impl/*.java| \ */org/olap4j/impl/Base64.java) return ;; # Exceptions for farrago */farrago/classes/* | \ */farrago/catalog/* | \ */farrago/examples/rng/src/net/sf/farrago/rng/parserimpl/*.java | \ */farrago/examples/rng/src/net/sf/farrago/rng/resource/FarragoRngResource*.java | \ */farrago/examples/rng/catalog/net/sf/farrago/rng/rngmodel/* | \ */farrago/examples/rng/catalog/java/* | \ */farrago/jdbc4/*.java | \ */farrago/src/net/sf/farrago/FarragoMetadataFactoryImpl.java | \ */farrago/src/net/sf/farrago/FarragoMetadataFactory.java | \ */farrago/src/net/sf/farrago/parser/impl/*.java | \ */farrago/src/net/sf/farrago/resource/FarragoResource*.java | \ */farrago/src/net/sf/farrago/resource/FarragoInternalQuery*.java | \ */farrago/src/net/sf/farrago/test/FarragoSqlTestWrapper.java | \ */farrago/src/org/eigenbase/jdbc4/*.java | \ */farrago/src/org/eigenbase/lurql/parser/*.java | \ */farrago/src/com/lucidera/lurql/parser/*.java | \ */farrago/src/org/eigenbase/resource/EigenbaseResource*.java | \ */farrago/src/org/eigenbase/sql/parser/impl/*.java) return ;; # Exceptions for fennel */fennel/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp | \ */fennel/disruptivetech/calc/CalcGrammar.tab.cpp | \ */fennel/disruptivetech/calc/CalcGrammar.cpp | \ */fennel/disruptivetech/calc/CalcGrammar.h | \ */fennel/disruptivetech/calc/CalcLexer.cpp | \ */fennel/disruptivetech/calc/CalcLexer.h | \ */fennel/calculator/CalcGrammar.tab.cpp | \ */fennel/calculator/CalcGrammar.cpp | \ */fennel/calculator/CalcGrammar.h | \ */fennel/calculator/CalcLexer.cpp | \ */fennel/calculator/CalcLexer.h | \ */fennel/common/FemGeneratedEnums.h | \ */fennel/common/FennelResource.cpp | \ */fennel/common/FennelResource.h | \ */fennel/config.h | \ */fennel/farrago/FemGeneratedClasses.h | \ */fennel/farrago/FemGeneratedMethods.h | \ */fennel/farrago/NativeMethods.h) return ;; # Skip our own test files, unless we are testing. */util/test/CheckFile1.*) if [ ! "$test" ]; then return fi ;; # Only validate .java and .cup files at present. *.java|*.cup|*.h|*.cpp) ;; *) return ;; esac # Set maxLineLength if it is not already set. ('checkFile --opened' # sets it to the strictest value, 80). if [ ! "$maxLineLength" ]; then maxLineLength=80 fi # Check whether there are tabs, or lines end with spaces # todo: check for ' ;' # todo: check that every file has copyright/license header # todo: check that every class has javadoc # todo: check that every top-level class has @author and @version # todo: check c++ files if test "$deferred" ; then echo "$file" >> "${deferred_file}" else gawk -f "$CHECKFILE_AWK" \ -v fname="$filePath" \ -v lenient="$lenient" \ -v maxLineLength="$maxLineLength" \ "$file" fi } doCheckDeferred() { if [ -s "${deferred_file}" ]; then maxLineLength=80 cat "${deferred_file}" | xargs gawk -f "$CHECKFILE_AWK" \ -v lenient="$lenient" \ -v maxLineLength="$maxLineLength" fi rm -f "${deferred_file}" } export deferred=true # 'test' is an undocumented flag, overriding the default behavior which is # to ignore our own test files test= if [ "$1" == --test ]; then test=true shift fi lenient= if [ "$1" == --lenient ]; then lenient=true shift fi if [ "$1" == --help ]; then usage exit 0 fi strict= if [ "$1" == --strict ]; then strict=true shift fi depotPath= if [ "$1" == --depotPath ]; then depotPath="$2" deferred= shift 2 fi opened= if [ "$1" == --opened ]; then opened=true deferred= shift fi under= if [ "$1" == --under ]; then if [ "$opened" ]; then echo "Cannot specify both --under and --opened" exit 1 fi if [ ! -d "$2" ]; then echo "--under requires a directory; '$2' not found" exit 1 fi under="$2" shift 2 fi if [ "$1" == --opened ]; then echo "Cannot specify both --under and --opened" exit 1 fi if [ ! -f "$CHECKFILE_AWK" ] then export CHECKFILE_AWK="$(dirname $(readlink -f $0))/checkFile.awk" fi export deferred_file=/tmp/checkFile_deferred_$$.txt rm -f "${deferred_file}" ( if [ "$under" ]; then find "$under" -type f | while read file; do filePath="$file" if [ "$depotPath" ]; then filePath="$depotPath" fi doCheck "$filePath" "$file" "" done elif [ "$opened" ]; then p4 opened | gawk -F'#' '$2 !~ / - delete/ {print $1}' | while read line; do file=$(p4 where "$line" | gawk '{print $3}' | tr \\\\ /) doCheck "$file" "$file" "80" done else for file in "$@"; do filePath="$file" if [ "$depotPath" ]; then filePath="$depotPath" fi doCheck "$filePath" "$file" "" done fi if test "$deferred"; then doCheckDeferred fi ) | tee /tmp/checkFile_output_$$.txt status=0 if [ -s /tmp/checkFile_output_$$.txt ]; then status=1 fi exit $status # End checkFile.sh olap4j-1.0.1.500/xmla-cache/0000755000175000017500000000000011542120414015075 5ustar drazzibdrazzibolap4j-1.0.1.500/ivy-tck.xml0000644000175000017500000000571011707507674015232 0ustar drazzibdrazzib TCK for olap4j. olap4j-1.0.1.500/src/0000755000175000017500000000000011426470544013677 5ustar drazzibdrazzibolap4j-1.0.1.500/src/META-INF/0000755000175000017500000000000011421322444015025 5ustar drazzibdrazzibolap4j-1.0.1.500/src/META-INF/services/0000755000175000017500000000000011421322444016650 5ustar drazzibdrazzibolap4j-1.0.1.500/src/META-INF/services/java.sql.Driver0000644000175000017500000000005011421322444021537 0ustar drazzibdrazziborg.olap4j.driver.xmla.XmlaOlap4jDriver olap4j-1.0.1.500/src/overview.html0000644000175000017500000000061711421322454016426 0ustar drazzibdrazzib

olap4j is an open Java API for OLAP.

Resources:

olap4j-1.0.1.500/src/org/0000755000175000017500000000000011421322444014454 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/0000755000175000017500000000000011541203614015645 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/Scenario.java0000644000175000017500000000372511707255012020265 0ustar drazzibdrazzib/* // $Id: Scenario.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; /** * Context for a set of writeback operations. * *

An analyst performing a what-if analysis would first create a scenario, * or open an existing scenario, then modify a sequence of cell values. * *

Some OLAP engines allow scenarios to be saved (to a file, or perhaps to * the database) and restored in a future session. * *

Multiple scenarios may be open at the same time, by different users of * the OLAP engine. * * @see OlapConnection#createScenario() * @see OlapConnection#setScenario(Scenario) * @see OlapConnection#getScenario() * @see Cell#setValue(Object, AllocationPolicy, Object[]) * @see AllocationPolicy * * @author jhyde * @since 24 April, 2009 * @version $Id: Scenario.java 482 2012-01-05 23:27:27Z jhyde $ */ public interface Scenario { /** * Returns the unique identifier of this Scenario. * *

The format of the string returned is implementation defined. Client * applications must not make any assumptions about the structure or * contents of such strings. * * @return Unique identifier of this Scenario. */ String getId(); } // End Scenario.java olap4j-1.0.1.500/src/org/olap4j/OlapException.java0000644000175000017500000002166111707255012021273 0ustar drazzibdrazzib/* // $Id: OlapException.java 485 2012-01-17 06:57:57Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import java.sql.*; /** *

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: OlapException.java 485 2012-01-17 06:57:57Z jhyde $ * @since Oct 23, 2006 */ public class OlapException extends SQLException { private Region region; private Object context; /** * Constructs an OlapException object with a given * reason, SQLState and * vendorCode. * * @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 OlapException 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 OlapException 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 OlapException object; * the reason field defaults to null, * the sqlState field defaults to null, and * the vendorCode field defaults to 0. */ public OlapException() { super(); } /** * Constructs an OlapException object with a given * cause. * The SQLState is initialized * to null and the vendor code is initialized to 0. * The reason is initialized to null if * cause==null or to cause.toString() if * cause!=null. *

* @param cause the underlying reason for this OlapException * (which is saved for later retrieval by the getCause() * method); may be null indicating the cause is non-existent or unknown. */ public OlapException(Throwable cause) { super(); initCause(cause); } /** * Constructs an OlapException object with a given * reason and cause. * * @param reason the detail message (which is saved for later retrieval * by the {@link #getMessage()} method). * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public OlapException(String reason, Throwable cause) { // Cannot call super(reason, cause) because // SQLException(String, Throwable) only exists from JDK 1.6. super(reason); initCause(cause); } /** * Constructs an OlapException object with a given * reason, SQLState and cause. * The vendor code is initialized to 0. * * @param reason a description of the exception. * @param sqlState an XOPEN or SQL:2003 code identifying the exception * @param cause the underlying reason for this OlapException * (which is saved for later retrieval by the * getCause() method); may be null indicating * the cause is non-existent or unknown. */ public OlapException(String reason, String sqlState, Throwable cause) { // Cannot call SQLException(String, String, Throwable); it only // exists from JDK 1.6 super(reason, sqlState); initCause(cause); } /** * Constructs an OlapException object with a given * reason, SQLState, vendorCode * and cause. * * @param reason a description of the exception * @param sqlState an XOPEN or SQL:2003 code identifying the exception * @param vendorCode a database vendor-specific exception code * @param cause the underlying reason for this OlapException * (which is saved for later retrieval by the getCause() * method); * may be null indicating the cause is non-existent or unknown. */ public OlapException( String reason, String sqlState, int vendorCode, Throwable cause) { // Cannot call SQLException(String, String, int, Throwable); it only // exists from JDK 1.6 super(reason, sqlState, vendorCode); initCause(cause); } /** * Sets the textual region where the exception occurred. * * @param region Textual region */ public void setRegion(Region region) { this.region = region; } /** * Returns the textual region where the exception occurred, or null if no * region can be identified. * * @return Region where the exception occurred */ 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 Cell} * or a {@link Position} */ public void setContext(Object context) { if (!(context instanceof Cell) && !(context instanceof Position)) { throw new IllegalArgumentException( "expected Cell or Position"); } this.context = context; } /** * Returns the context where the exception occurred. * Typically a {@link Cell} or a {@link Position}, or null. * * @return context where the exception occurred, 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 olap4j-1.0.1.500/src/org/olap4j/package.html0000644000175000017500000000020211421322454020121 0ustar drazzibdrazzib Provides the core classes and interfaces of the olap4j API for accessing and processing OLAP data. olap4j-1.0.1.500/src/org/olap4j/CellSetAxis.java0000644000175000017500000001045411707255012020677 0ustar drazzibdrazzib/* // $Id: CellSetAxis.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import java.util.List; import java.util.ListIterator; /** * Axis of a CellSet. * *

A cell set has the same number of axes as the MDX statement which was * executed to produce it. For example, a typical cell set, resulting from an * MDX query with COLUMNS and ROWS expressions is two-dimensional, and * therefore has two axes.

* *

Each axis is an ordered collection of members or tuples. Each member or * tuple on an axis is called a {@link Position}.

* *

The positions on the cell set axis can be accessed sequentially or * random-access. Use the {@link #getPositions()} method to return a list for * random access, or the {@link #iterator()} method to obtain an iterator for * sequential access. * * @author jhyde * @version $Id: CellSetAxis.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface CellSetAxis extends Iterable { /** * Returns the axis ordinal of this CellSetAxis. * *

The first axis in a CellSet will return {@link Axis#COLUMNS}, * the second {@link Axis#ROWS}, and so forth, as described by the * {@link Axis#axisOrdinal()} method of the {@link Axis} enumeration.

* * @return the ordinal of this axis */ Axis getAxisOrdinal(); /** * Returns the {@link CellSet} which this CellSetAxis * belongs to. * * @return the CellSet */ CellSet getCellSet(); /** * 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 *

* getCellSet().getMetaData().getSlicerAxisMetaData() *
* for a filter axis, and *
* getCellSet().getMetaData().getAxesMetaData().get( * getAxisOrdinal().axisOrdinal()) *
* for other axes. * * @return metadata describing this CellSetAxis */ CellSetAxisMetaData getAxisMetaData(); /** * Returns a list of Position objects on this CellSetAxis. * * @return List of positions on this axis (never null) */ List getPositions(); /** * Returns the number of positions on this CellSetAxis. * *

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.

* * @return the number of positions */ int getPositionCount(); /** * Opens an iterator over the positions on this CellSetAxis. * *

If this axis has very many positions, this method may be more * efficient than {@link #getPositions()}. * *

This method allows CellSetAxis to implement the {@link Iterable} * interface, so one might use it in a foreach construct, for example: * *

*
     * CellSet cellSet;
     * for (Position rowPos : cellSet.getAxes().get(0)) {
     *     for (Position colPos : cellSet.getAxes().get(1)) {
     *          Cell cell = cellSet.getCell(colPos, rowPos);
     *          ....
     *     }
     * }
* * @return iterator over the collection of positions */ ListIterator iterator(); } // End CellSetAxis.java olap4j-1.0.1.500/src/org/olap4j/OlapDataSource.java0000644000175000017500000000332411707255012021363 0ustar drazzibdrazzib/* // $Id: OlapDataSource.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import java.sql.SQLException; import javax.sql.DataSource; /** *

A factory for connections to the physical OLAP data source that this * OlapDataSource object represents. * *

OlapDataSource is a refinement of * {@link javax.sql.DataSource} whose getConnection methods * return {@link org.olap4j.OlapConnection} objects rather than mere * {@link java.sql.Connection}s. * * @author jhyde * @version $Id: OlapDataSource.java 482 2012-01-05 23:27:27Z jhyde $ * @since Mar 25, 2008 */ public interface OlapDataSource extends DataSource { // override with more specific return type OlapConnection getConnection() throws SQLException; // override with more specific return type OlapConnection getConnection( String username, String password) throws SQLException; } // End OlapDataSource.java olap4j-1.0.1.500/src/org/olap4j/layout/0000755000175000017500000000000011421322454017163 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/layout/CellSetFormatter.java0000644000175000017500000000273611707255012023257 0ustar drazzibdrazzib/* // $Id: CellSetFormatter.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.layout; import org.olap4j.CellSet; import java.io.PrintWriter; /** * Converts a {@link CellSet} into text. * *

This interface is experimental. It is not part of the olap4j * specification and is subject to change without notice.

* * @author jhyde * @version $Id: CellSetFormatter.java 482 2012-01-05 23:27:27Z jhyde $ * @since Apr 15, 2009 */ public interface CellSetFormatter { /** * Formats a CellSet as text to a PrintWriter. * * @param cellSet Cell set * @param pw Print writer */ void format( CellSet cellSet, PrintWriter pw); } // End CellSetFormatter.java olap4j-1.0.1.500/src/org/olap4j/layout/package.html0000644000175000017500000000033711421322454021447 0ustar drazzibdrazzib Provides utility classes to display and render olap4j specific data structures.

NOTE: This package is experimental. Classes may be renamed or removed in a future release of olap4j. olap4j-1.0.1.500/src/org/olap4j/layout/TraditionalCellSetFormatter.java0000644000175000017500000001077511707255012025454 0ustar drazzibdrazzib/* // $Id: TraditionalCellSetFormatter.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.layout; import org.olap4j.*; import org.olap4j.metadata.Member; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** * Formatter that can convert a {@link CellSet} into Mondrian's traditional * layout. * *

This class is experimental. It is not part of the olap4j * specification and is subject to change without notice.

* * @author jhyde * @version $Id: TraditionalCellSetFormatter.java 482 2012-01-05 23:27:27Z jhyde $ * @since Apr 15, 2009 */ public class TraditionalCellSetFormatter implements CellSetFormatter { public void format( CellSet cellSet, PrintWriter pw) { print(cellSet, pw); } /** * Prints a cell set. * * @param cellSet Cell set * @param pw Writer */ private static void print(CellSet cellSet, PrintWriter pw) { pw.println("Axis #0:"); printAxis(pw, cellSet.getFilterAxis()); final List axes = cellSet.getAxes(); final int axisCount = axes.size(); for (int i = 0; i < axisCount; i++) { CellSetAxis axis = axes.get(i); pw.println("Axis #" + (i + 1) + ":"); printAxis(pw, axis); } // Usually there are 3 axes: {filter, columns, rows}. Position is a // {column, row} pair. We call printRows with axis=2. When it // recurses to axis=-1, it prints. List pos = new ArrayList(axisCount); for (int i = 0; i < axisCount; i++) { pos.add(-1); } if (axisCount == 0) { printCell(cellSet, pw, pos); } else { printRows(cellSet, pw, axisCount - 1, pos); } } /** * Prints the rows of cell set. * * @param cellSet Cell set * @param pw Writer * @param axis Axis ordinal * @param pos Partial coordinate */ private static void printRows( CellSet cellSet, PrintWriter pw, int axis, List pos) { final CellSetAxis _axis = cellSet.getAxes().get(axis); final List positions = _axis.getPositions(); final int positionCount = positions.size(); for (int i = 0; i < positionCount; i++) { pos.set(axis, i); if (axis == 0) { int row = axis + 1 < pos.size() ? pos.get(axis + 1) : 0; pw.print("Row #" + row + ": "); printCell(cellSet, pw, pos); pw.println(); } else { printRows(cellSet, pw, axis - 1, pos); } } } /** * Prints an axis and its members. * * @param pw Print writer * @param axis Axis */ private static void printAxis(PrintWriter pw, CellSetAxis axis) { List positions = axis.getPositions(); for (Position position : positions) { boolean firstTime = true; pw.print("{"); for (Member member : position.getMembers()) { if (! firstTime) { pw.print(", "); } pw.print(member.getUniqueName()); firstTime = false; } pw.println("}"); } } /** * Prints the formatted value of a Cell at a given position. * * @param cellSet Cell set * @param pw Print writer * @param pos Cell coordinates */ private static void printCell( CellSet cellSet, PrintWriter pw, List pos) { Cell cell = cellSet.getCell(pos); pw.print(cell.getFormattedValue()); } } // End TraditionalCellSetFormatter.java olap4j-1.0.1.500/src/org/olap4j/layout/RectangularCellSetFormatter.java0000644000175000017500000005176511707255012025455 0ustar drazzibdrazzib/* // $Id: RectangularCellSetFormatter.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.layout; import org.olap4j.*; import org.olap4j.impl.CoordinateIterator; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.Member; import java.io.PrintWriter; import java.util.*; /** * Formatter that can convert a {@link CellSet} into a two-dimensional text * layout. * *

With non-compact layout: * *

 *                    | 1997                                                |
 *                    | Q1                       | Q2                       |
 *                    |                          | 4                        |
 *                    | Unit Sales | Store Sales | Unit Sales | Store Sales |
 * ----+----+---------+------------+-------------+------------+-------------+
 * USA | CA | Modesto |         12 |        34.5 |         13 |       35.60 |
 *     | WA | Seattle |         12 |        34.5 |         13 |       35.60 |
 *     | CA | Fresno  |         12 |        34.5 |         13 |       35.60 |
 * 
* *

With compact layout: *

 *
 *                1997
 *                Q1                     Q2
 *                                       4
 *                Unit Sales Store Sales Unit Sales Store Sales
 * === == ======= ========== =========== ========== ===========
 * USA CA Modesto         12        34.5         13       35.60
 *     WA Seattle         12        34.5         13       35.60
 *     CA Fresno          12        34.5         13       35.60
 * 
* *

This class is experimental. It is not part of the olap4j * specification and is subject to change without notice.

* * @author jhyde * @version $Id: RectangularCellSetFormatter.java 482 2012-01-05 23:27:27Z jhyde $ * @since Apr 15, 2009 */ public class RectangularCellSetFormatter implements CellSetFormatter { private final boolean compact; /** * Creates a RectangularCellSetFormatter. * * @param compact Whether to generate compact output */ public RectangularCellSetFormatter(boolean compact) { this.compact = compact; } public void format(CellSet cellSet, PrintWriter pw) { // Compute how many rows are required to display the columns axis. // In the example, this is 4 (1997, Q1, space, Unit Sales) final CellSetAxis columnsAxis; if (cellSet.getAxes().size() > 0) { columnsAxis = cellSet.getAxes().get(0); } else { columnsAxis = null; } AxisInfo columnsAxisInfo = computeAxisInfo(columnsAxis); // Compute how many columns are required to display the rows axis. // In the example, this is 3 (the width of USA, CA, Los Angeles) final CellSetAxis rowsAxis; if (cellSet.getAxes().size() > 1) { rowsAxis = cellSet.getAxes().get(1); } else { rowsAxis = null; } AxisInfo rowsAxisInfo = computeAxisInfo(rowsAxis); if (cellSet.getAxes().size() > 2) { int[] dimensions = new int[cellSet.getAxes().size() - 2]; for (int i = 2; i < cellSet.getAxes().size(); i++) { CellSetAxis cellSetAxis = cellSet.getAxes().get(i); dimensions[i - 2] = cellSetAxis.getPositions().size(); } for (int[] pageCoords : CoordinateIterator.iterate(dimensions)) { formatPage( cellSet, pw, pageCoords, columnsAxis, columnsAxisInfo, rowsAxis, rowsAxisInfo); } } else { formatPage( cellSet, pw, new int[] {}, columnsAxis, columnsAxisInfo, rowsAxis, rowsAxisInfo); } } /** * Formats a two-dimensional page. * * @param cellSet Cell set * @param pw Print writer * @param pageCoords Coordinates of page [page, chapter, section, ...] * @param columnsAxis Columns axis * @param columnsAxisInfo Description of columns axis * @param rowsAxis Rows axis * @param rowsAxisInfo Description of rows axis */ private void formatPage( CellSet cellSet, PrintWriter pw, int[] pageCoords, CellSetAxis columnsAxis, AxisInfo columnsAxisInfo, CellSetAxis rowsAxis, AxisInfo rowsAxisInfo) { if (pageCoords.length > 0) { pw.println(); for (int i = pageCoords.length - 1; i >= 0; --i) { int pageCoord = pageCoords[i]; final CellSetAxis axis = cellSet.getAxes().get(2 + i); pw.print(axis.getAxisOrdinal() + ": "); final Position position = axis.getPositions().get(pageCoord); int k = -1; for (Member member : position.getMembers()) { if (++k > 0) { pw.print(", "); } pw.print(member.getUniqueName()); } pw.println(); } } // Figure out the dimensions of the blank rectangle in the top left // corner. final int yOffset = columnsAxisInfo.getWidth(); final int xOffsset = rowsAxisInfo.getWidth(); // Populate a string matrix Matrix matrix = new Matrix( xOffsset + (columnsAxis == null ? 1 : columnsAxis.getPositions().size()), yOffset + (rowsAxis == null ? 1 : rowsAxis.getPositions().size())); // Populate corner for (int x = 0; x < xOffsset; x++) { for (int y = 0; y < yOffset; y++) { matrix.set(x, y, "", false, x > 0); } } // Populate matrix with cells representing axes //noinspection SuspiciousNameCombination populateAxis( matrix, columnsAxis, columnsAxisInfo, true, xOffsset); populateAxis( matrix, rowsAxis, rowsAxisInfo, false, yOffset); // Populate cell values for (Cell cell : cellIter(pageCoords, cellSet)) { final List coordList = cell.getCoordinateList(); int x = xOffsset; if (coordList.size() > 0) { x += coordList.get(0); } int y = yOffset; if (coordList.size() > 1) { y += coordList.get(1); } matrix.set( x, y, cell.getFormattedValue(), true, false); } int[] columnWidths = new int[matrix.width]; int widestWidth = 0; for (int x = 0; x < matrix.width; x++) { int columnWidth = 0; for (int y = 0; y < matrix.height; y++) { MatrixCell cell = matrix.get(x, y); if (cell != null) { columnWidth = Math.max(columnWidth, cell.value.length()); } } columnWidths[x] = columnWidth; widestWidth = Math.max(columnWidth, widestWidth); } // Create a large array of spaces, for efficient printing. char[] spaces = new char[widestWidth + 1]; Arrays.fill(spaces, ' '); char[] equals = new char[widestWidth + 1]; Arrays.fill(equals, '='); char[] dashes = new char[widestWidth + 3]; Arrays.fill(dashes, '-'); if (compact) { for (int y = 0; y < matrix.height; y++) { for (int x = 0; x < matrix.width; x++) { if (x > 0) { pw.print(' '); } final MatrixCell cell = matrix.get(x, y); final int len; if (cell != null) { if (cell.sameAsPrev) { len = 0; } else { if (cell.right) { int padding = columnWidths[x] - cell.value.length(); pw.write(spaces, 0, padding); pw.print(cell.value); continue; } pw.print(cell.value); len = cell.value.length(); } } else { len = 0; } if (x == matrix.width - 1) { // at last column; don't bother to print padding break; } int padding = columnWidths[x] - len; pw.write(spaces, 0, padding); } pw.println(); if (y == yOffset - 1) { for (int x = 0; x < matrix.width; x++) { if (x > 0) { pw.write(' '); } pw.write(equals, 0, columnWidths[x]); } pw.println(); } } } else { for (int y = 0; y < matrix.height; y++) { for (int x = 0; x < matrix.width; x++) { final MatrixCell cell = matrix.get(x, y); final int len; if (cell != null) { if (cell.sameAsPrev) { pw.print(" "); len = 0; } else { pw.print("| "); if (cell.right) { int padding = columnWidths[x] - cell.value.length(); pw.write(spaces, 0, padding); pw.print(cell.value); pw.print(' '); continue; } pw.print(cell.value); len = cell.value.length(); } } else { pw.print("| "); len = 0; } int padding = columnWidths[x] - len; ++padding; pw.write(spaces, 0, padding); } pw.println('|'); if (y == yOffset - 1) { for (int x = 0; x < matrix.width; x++) { pw.write('+'); pw.write(dashes, 0, columnWidths[x] + 2); } pw.println('+'); } } } } /** * Populates cells in the matrix corresponding to a particular axis. * * @param matrix Matrix to populate * @param axis Axis * @param axisInfo Description of axis * @param isColumns True if columns, false if rows * @param offset Ordinal of first cell to populate in matrix */ private void populateAxis( Matrix matrix, CellSetAxis axis, AxisInfo axisInfo, boolean isColumns, int offset) { if (axis == null) { return; } Member[] prevMembers = new Member[axisInfo.getWidth()]; Member[] members = new Member[axisInfo.getWidth()]; for (int i = 0; i < axis.getPositions().size(); i++) { final int x = offset + i; Position position = axis.getPositions().get(i); int yOffset = 0; final List memberList = position.getMembers(); for (int j = 0; j < memberList.size(); j++) { Member member = memberList.get(j); final AxisOrdinalInfo ordinalInfo = axisInfo.ordinalInfos.get(j); while (member != null) { if (member.getDepth() < ordinalInfo.minDepth) { break; } final int y = yOffset + member.getDepth() - ordinalInfo.minDepth; members[y] = member; member = member.getParentMember(); } yOffset += ordinalInfo.getWidth(); } boolean same = true; for (int y = 0; y < members.length; y++) { Member member = members[y]; same = same && i > 0 && Olap4jUtil.equal(prevMembers[y], member); String value = member == null ? "" : member.getCaption(); if (isColumns) { matrix.set(x, y, value, false, same); } else { if (same) { value = ""; } //noinspection SuspiciousNameCombination matrix.set(y, x, value, false, false); } prevMembers[y] = member; members[y] = null; } } } /** * Computes a description of an axis. * * @param axis Axis * @return Description of axis */ private AxisInfo computeAxisInfo(CellSetAxis axis) { if (axis == null) { return new AxisInfo(0); } final AxisInfo axisInfo = new AxisInfo(axis.getAxisMetaData().getHierarchies().size()); int p = -1; for (Position position : axis.getPositions()) { ++p; int k = -1; for (Member member : position.getMembers()) { ++k; final AxisOrdinalInfo axisOrdinalInfo = axisInfo.ordinalInfos.get(k); final int topDepth = member.isAll() ? member.getDepth() : member.getHierarchy().hasAll() ? 1 : 0; if (axisOrdinalInfo.minDepth > topDepth || p == 0) { axisOrdinalInfo.minDepth = topDepth; } axisOrdinalInfo.maxDepth = Math.max( axisOrdinalInfo.maxDepth, member.getDepth()); } } return axisInfo; } /** * Returns an iterator over cells in a result. */ private static Iterable cellIter( final int[] pageCoords, final CellSet cellSet) { return new Iterable() { public Iterator iterator() { int[] axisDimensions = new int[cellSet.getAxes().size() - pageCoords.length]; assert pageCoords.length <= axisDimensions.length; for (int i = 0; i < axisDimensions.length; i++) { CellSetAxis axis = cellSet.getAxes().get(i); axisDimensions[i] = axis.getPositions().size(); } final CoordinateIterator coordIter = new CoordinateIterator(axisDimensions, true); return new Iterator() { public boolean hasNext() { return coordIter.hasNext(); } public Cell next() { final int[] ints = coordIter.next(); final AbstractList intList = new AbstractList() { public Integer get(int index) { return index < ints.length ? ints[index] : pageCoords[index - ints.length]; } public int size() { return pageCoords.length + ints.length; } }; return cellSet.getCell(intList); } public void remove() { throw new UnsupportedOperationException(); } }; } }; } /** * Description of a particular hierarchy mapped to an axis. */ private static class AxisOrdinalInfo { int minDepth = 1; int maxDepth = 0; /** * Returns the number of matrix columns required to display this * hierarchy. */ public int getWidth() { return maxDepth - minDepth + 1; } } /** * Description of an axis. */ private static class AxisInfo { final List ordinalInfos; /** * Creates an AxisInfo. * * @param ordinalCount Number of hierarchies on this axis */ AxisInfo(int ordinalCount) { ordinalInfos = new ArrayList(ordinalCount); for (int i = 0; i < ordinalCount; i++) { ordinalInfos.add(new AxisOrdinalInfo()); } } /** * Returns the number of matrix columns required by this axis. The * sum of the width of the hierarchies on this axis. * * @return Width of axis */ public int getWidth() { int width = 0; for (AxisOrdinalInfo info : ordinalInfos) { width += info.getWidth(); } return width; } } /** * Two-dimensional collection of string values. */ private class Matrix { private final Map, MatrixCell> map = new HashMap, MatrixCell>(); private final int width; private final int height; /** * Creats a Matrix. * * @param width Width of matrix * @param height Height of matrix */ public Matrix(int width, int height) { this.width = width; this.height = height; } /** * Sets the value at a particular coordinate * * @param x X coordinate * @param y Y coordinate * @param value Value */ void set(int x, int y, String value) { set(x, y, value, false, false); } /** * Sets the value at a particular coordinate * * @param x X coordinate * @param y Y coordinate * @param value Value * @param right Whether value is right-justified * @param sameAsPrev Whether value is the same as the previous value. * If true, some formats separators between cells */ void set( int x, int y, String value, boolean right, boolean sameAsPrev) { map.put( Arrays.asList(x, y), new MatrixCell(value, right, sameAsPrev)); assert x >= 0 && x < width : x; assert y >= 0 && y < height : y; } /** * Returns the cell at a particular coordinate. * * @param x X coordinate * @param y Y coordinate * @return Cell */ public MatrixCell get(int x, int y) { return map.get(Arrays.asList(x, y)); } } /** * Contents of a cell in a matrix. */ private static class MatrixCell { final String value; final boolean right; final boolean sameAsPrev; /** * Creates a matrix cell. * * @param value Value * @param right Whether value is right-justified * @param sameAsPrev Whether value is the same as the previous value. * If true, some formats separators between cells */ MatrixCell( String value, boolean right, boolean sameAsPrev) { this.value = value; this.right = right; this.sameAsPrev = sameAsPrev; } } } // End RectangularCellSetFormatter.java olap4j-1.0.1.500/src/org/olap4j/PreparedOlapStatement.java0000644000175000017500000001276111707255012022765 0ustar drazzibdrazzib/* // $Id: PreparedOlapStatement.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.metadata.Cube; import java.sql.PreparedStatement; import java.sql.SQLException; /** * An object that represents a precompiled OLAP statement. * *

An OLAP statement is precompiled and stored in a * PreparedOlapStatement object. This object can then be used to * efficiently execute this statement multiple times.

* *

A PreparedOlapStatement is generally created using * {@link OlapConnection#prepareOlapStatement(String)}.

* *

Note: The setter methods (setShort, * setString, and so on) for setting IN parameter values * must specify types that are compatible with the defined type of * the input parameter. For instance, if the IN parameter has type * INTEGER, then the method setInt should be used.

* *

If a parameter has Member type, use the {@link #setObject(int, Object)} * method to set it. A {@link OlapException} will be thrown if the object is not * an instance of {@link org.olap4j.metadata.Member} or does not belong to the * correct {@link org.olap4j.metadata.Hierarchy}.

* *

The method {@link #getParameterMetaData()} returns a description of the * parameters, as in JDBC. The result is an {@link OlapParameterMetaData}. * *

Unlike JDBC, it is not necessary to assign a value to every parameter. * This is because OLAP parameters have a default value. Parameters have their * default value until they are set, and then retain their new values for each * subsequent execution of this PreparedOlapStatement. * * @see OlapConnection#prepareOlapStatement(String) * @see CellSet * * @author jhyde * @version $Id: PreparedOlapStatement.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface PreparedOlapStatement extends PreparedStatement, OlapStatement { /** * Executes the MDX query in this PreparedOlapStatement object * and returns the CellSet object generated by the query. * * @return an CellSet object that contains the data produced * by the query; never null * @exception OlapException if a database access error occurs */ CellSet executeQuery() throws OlapException; /** * Retrieves the number, types and properties of this * PreparedOlapStatement object's parameters. * * @return an OlapParameterMetaData object that contains * information about the number, types and properties of this * PreparedOlapStatement object's parameters * @exception OlapException if a database access error occurs * @see OlapParameterMetaData */ OlapParameterMetaData getParameterMetaData() throws OlapException; /** * Retrieves a CellSetMetaData object that contains * information about the axes and cells of the CellSet object * that will be returned when this PreparedOlapStatement object * is executed. * * @return the description of this CellSet's axes * and cells * @exception OlapException if a database access error occurs */ CellSetMetaData getMetaData() throws SQLException; /** * Returns the cube (or virtual cube) which this statement is based upon. * * @return cube this statement is based upon */ Cube getCube(); /** * Returns whether the value of the designated parameter is set. * *

Note that you cannot tell whether the parameter is set by looking to * see whether the value is {@code null}, because {@code null} is a valid * parameter value. When a parameter is not set, its value is derived by * evaluating its default expression. * *

To set the value call one of the {@link #setObject setXxx} methods. To * unset the value, call {@link #unset}. * * @param parameterIndex the first parameter is 1, the second is 2, ... * @return whether the parameter's value has been set * @exception java.sql.SQLException if a database access error occurs */ boolean isSet(int parameterIndex) throws SQLException; /** * Unsets the value of the designated parameter. * * @see #isSet(int) * * @param parameterIndex the first parameter is 1, the second is 2, ... * @exception java.sql.SQLException if a database access error occurs */ void unset(int parameterIndex) throws SQLException; } // End PreparedOlapStatement.java olap4j-1.0.1.500/src/org/olap4j/sample/0000755000175000017500000000000011424005356017131 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/sample/package.html0000644000175000017500000000020011421322444021377 0ustar drazzibdrazzib Contains sample code which use the olap4j API.

Not part of the olap4j public API.

olap4j-1.0.1.500/src/org/olap4j/sample/SimpleQuerySample.java0000644000175000017500000002532111707254774023436 0ustar drazzibdrazzib/* // $Id: SimpleQuerySample.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.sample; import org.olap4j.*; import org.olap4j.layout.RectangularCellSetFormatter; import org.olap4j.mdx.*; import org.olap4j.mdx.parser.MdxParser; import org.olap4j.mdx.parser.MdxParserFactory; import org.olap4j.metadata.Dimension; import org.olap4j.metadata.Member; import org.olap4j.type.MemberType; import java.io.PrintWriter; import java.sql.*; import java.util.ArrayList; import java.util.List; /** * Collection of olap4j samples illustrating connections and statements. * * @author jhyde * @version $Id: SimpleQuerySample.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public class SimpleQuerySample { /** * Main command-line entry. * * @param args Command line arguments */ public static void main(String[] args) { try { new SimpleQuerySample().simpleStatement(); } catch (OlapException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * Simple example which connects to an OLAP server, executes an OLAP * statement and prints the resulting cell set. */ void simpleStatement() throws SQLException, ClassNotFoundException { // Register driver. Class.forName("mondrian.olap4j.MondrianOlap4jDriver"); // Create connection. Connection connection = DriverManager.getConnection("jdbc:mondrian:embedded"); OlapConnection olapConnection = ((OlapWrapper) connection).unwrap(OlapConnection.class); // Execute a statement. OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery( "select {[Measures].[Unit Sales]} on columns,\n" + " CrossJoin([Store].Children, [Gender].Members) on rows\n" + "from [Sales]"); List cellSetAxes = cellSet.getAxes(); // Print headings. System.out.print("\t"); CellSetAxis columnsAxis = cellSetAxes.get(Axis.COLUMNS.axisOrdinal()); for (Position position : columnsAxis.getPositions()) { Member measure = position.getMembers().get(0); System.out.print(measure.getName()); } // Print rows. CellSetAxis rowsAxis = cellSetAxes.get(Axis.ROWS.axisOrdinal()); int cellOrdinal = 0; for (Position rowPosition : rowsAxis.getPositions()) { boolean first = true; for (Member member : rowPosition.getMembers()) { if (first) { first = false; } else { System.out.print('\t'); } System.out.print(member.getName()); } // Print the value of the cell in each column. for (Position columnPosition : columnsAxis.getPositions()) { // Access the cell via its ordinal. The ordinal is kept in step // because we increment the ordinal once for each row and // column. Cell cell = cellSet.getCell(cellOrdinal); // Just for kicks, convert the ordinal to a list of coordinates. // The list matches the row and column positions. List coordList = cellSet.ordinalToCoordinates(cellOrdinal); assert coordList.get(0) == rowPosition.getOrdinal(); assert coordList.get(1) == columnPosition.getOrdinal(); ++cellOrdinal; System.out.print('\t'); System.out.print(cell.getFormattedValue()); } System.out.println(); } // Now, nicely formatted. System.out.println(); final PrintWriter pw = new PrintWriter(System.out); new RectangularCellSetFormatter(false).format(cellSet, pw); pw.flush(); // Close the statement and connection. statement.close(); connection.close(); } /** * Sample which prepares a statement, sets a parameter, and executes the * statement. */ void preparedStatement() throws SQLException, ClassNotFoundException { // Register driver. Class.forName("mondrian.olap4j.Driver"); // Create connection. OlapConnection connection = (OlapConnection) DriverManager.getConnection("jdbc:mondrian:embedded"); // Prepare a statement. PreparedOlapStatement statement = connection.prepareOlapStatement( "select {[Measures].[Unit Sales]} on columns,\n" + " {TopCount\n(" + " Parameter(\"Store\", [Store].[USA].[CA]).Children,\n" + " Parameter(\"Count\", INTEGER))} on rows\n" + "from [Sales]"); // Describe the parameters. OlapParameterMetaData parameterMetaData = statement.getParameterMetaData(); // Locate the member "[Store].[USA].[WA].[Seattle]". MemberType type = (MemberType) parameterMetaData.getParameterOlapType(1); Dimension dimension = type.getDimension(); assert dimension.getName().equals("Store"); Member allStores = dimension.getDefaultHierarchy().getRootMembers().get(0); Member memberUsa = allStores.getChildMembers().get("USA"); Member memberWa = memberUsa.getChildMembers().get("WA"); Member memberSeattle = memberWa.getChildMembers().get("Seattle"); statement.setObject(1, memberSeattle); statement.setInt(2, 10); // Execute, and print cell set. CellSet cellSet = statement.executeQuery(); printCellSet(cellSet); // Close the statement and connection. statement.close(); connection.close(); } /** * Sample which creates a statement from a parse tree. */ void statementFromParseTree() throws ClassNotFoundException, SQLException { // Register driver. Class.forName("mondrian.olap4j.Driver"); // Create connection. Connection connection = DriverManager.getConnection("jdbc:mondrian:embedded"); OlapConnection olapConnection = ((OlapWrapper) connection).unwrap(OlapConnection.class); // Create a parser. MdxParserFactory parserFactory = olapConnection.getParserFactory(); MdxParser parser = parserFactory.createMdxParser(olapConnection); SelectNode query = parser.parseSelect( "select {[Measures].[Unit Sales]} on columns\n" + "from [Sales]"); query.getAxisList().get(0).setNonEmpty(false); // Create statement. OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery(query); printCellSet(cellSet); } /** * Prints a cell set. * *

For more sophisticated printing of cell sets, see * {@link org.olap4j.layout.CellSetFormatter}. * * @param cellSet Cell set */ private void printCellSet(CellSet cellSet) { List cellSetAxes = cellSet.getAxes(); // Print headings. System.out.print("\t"); CellSetAxis columnsAxis = cellSetAxes.get(Axis.COLUMNS.axisOrdinal()); for (Position position : columnsAxis.getPositions()) { Member measure = position.getMembers().get(0); System.out.print(measure.getName()); } // Print rows. CellSetAxis rowsAxis = cellSetAxes.get(Axis.ROWS.axisOrdinal()); List coordList = new ArrayList(2); int row = 0; for (Position 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 (Position columnPosition : columnsAxis.getPositions()) { assert columnPosition.getOrdinal() == column; coordList.set(1, column++); Cell cell = cellSet.getCell(coordList); System.out.print('\t'); System.out.print(cell.getFormattedValue()); } System.out.println(); } } /** * Example in "MDX query model" section of olap4j_fs.html. * * @param connection Connection */ void executeSelectNode(OlapConnection connection) { // Create a query model. SelectNode query = new SelectNode(); query.setFrom( new IdentifierNode( new NameSegment("Sales"))); query.getAxisList().add( new AxisNode( null, false, Axis.ROWS, new ArrayList(), new CallNode( null, "{}", Syntax.Braces, new IdentifierNode( new NameSegment("Measures"), new NameSegment("Unit Sales"))))); // Create a statement based upon the query model. OlapStatement stmt; try { stmt = connection.createStatement(); } catch (OlapException e) { System.out.println("Validation failed: " + e); return; } // Execute the statement. CellSet cset; try { cset = stmt.executeOlapQuery(query); printCellSet(cset); } catch (OlapException e) { System.out.println("Execution failed: " + e); } } } // End SimpleQuerySample.java olap4j-1.0.1.500/src/org/olap4j/sample/PaloConnection.java0000644000175000017500000000476611707254774022742 0ustar drazzibdrazzib/* // $Id: PaloConnection.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.sample; import org.olap4j.*; import org.olap4j.driver.xmla.XmlaOlap4jDriver; import org.olap4j.layout.RectangularCellSetFormatter; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; /** * This class demonstrates how to connect the {@link XmlaOlap4jDriver} * to a Palo server. Thanks to Vladislav Malicevic for this * contribution. * * @version $Id: PaloConnection.java 482 2012-01-05 23:27:27Z jhyde $ * @author Luc Boudreau */ public class PaloConnection { public static void main(String[] args) throws Exception { Class.forName("org.olap4j.driver.xmla.XmlaOlap4jDriver"); Connection connection = DriverManager.getConnection( "jdbc:xmla:Server=http://localhost:4242;" + "User='admin';" + "Password='admin';" + "Catalog=FoodMart2005Palo;" + "Cube=Budget"); OlapWrapper wrapper = (OlapWrapper) connection; OlapConnection olapConnection = wrapper.unwrap(OlapConnection.class); OlapStatement statement = olapConnection.createStatement(); CellSet cellSet = statement.executeOlapQuery( "SELECT {[store].[USA]} ON COLUMNS , {[Account].[1000]} ON ROWS\n" + "FROM [Budget]"); // We use the utility formatter. RectangularCellSetFormatter formatter = new RectangularCellSetFormatter(false); // Print out. PrintWriter writer = new PrintWriter(System.out); formatter.format(cellSet, writer); writer.flush(); statement.close(); connection.close(); } } // End PaloConnection.java olap4j-1.0.1.500/src/org/olap4j/CellSetAxisMetaData.java0000644000175000017500000000521611707255012022300 0ustar drazzibdrazzib/* // $Id: CellSetAxisMetaData.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.metadata.*; import java.util.List; /** * Description of structure of a particular axis of an {@link CellSet}. * *

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: CellSetAxisMetaData.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 23, 2006 */ public interface CellSetAxisMetaData { /** * Returns the definition of the axis. Typical values are * ({@link Axis#FILTER}, {@link Axis#COLUMNS}, {@link Axis#ROWS}, and so * forth.) * * @return the Axis */ Axis getAxisOrdinal(); /** * Returns the hierarchies which are mapped onto this axis. * * @return list of hierarchies on this Axis */ List getHierarchies(); /** * Returns the member properties which are returned on this axis. * *

This method does not return a {@link NamedList} because the names of * the properties are not necessarily unique; for example, there might be * two hierarchies on the axis, each of which returns the DISPLAY_INFO * property.

* * @return list of member properties on this Axis */ List getProperties(); } // End CellSetAxisMetaData.java olap4j-1.0.1.500/src/org/olap4j/CellSet.java0000644000175000017500000001500611707255012020050 0ustar drazzibdrazzib/* // $Id: CellSet.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; /** * Result of executing an OLAP Statement. * *

A CellSet 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: CellSet.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface CellSet extends ResultSet, OlapWrapper { /** * Retrieves the OlapStatement object that produced this * CellSet object. * If the result set was generated some other way, such as by a * {@link org.olap4j.OlapDatabaseMetaData} method, this method may return * null. * * @return the OlapStatment object that produced * this CellSet object or null * if the cell set was produced some other way * * @exception SQLException if a database access error occurs * or this method is called on a closed cell set */ OlapStatement getStatement() throws SQLException; /** * Retrieves the description of this CellSet's axes * and cells. * * @return the description of this CellSet's axes * and cells * @exception OlapException if a database access error occurs */ CellSetMetaData getMetaData() throws OlapException; /** * Retrieves a list of CellSetAxis objects containing the result. * *

The list contains axes according to their ordinal: 0 is the columns * axis, 1 the rows axis, and so forth. * * @return list of CellSetAxis objects containing the result * * @see #getFilterAxis() */ List getAxes(); /** * Retrieves the CellSetAxis representing the filter axis. * *

If the query has a WHERE clause, the contains the members returned * by that expression. Most query authors write a WHERE clause so that it * evaluates to just one member or tuple. The members in this tuple (or * the sole member), are referred to as the 'slicer context' of the query. * The tuple contains only members of hierarchies explicitly mentioned in * the WHERE expression; the slicer context of every hierarchy in the * query's cube is implicitly the default member of that hierarchy. * *

While not typical, note that a query's WHERE clause may also evaluate * to zero or more than one tuples. * *

If the query has no WHERE clause, the filter axis has a single * position, but the position has no members. * *

The filter axis is not included in the {@link #getAxes()} collection. * * @return the filter axis */ CellSetAxis getFilterAxis(); /** * Returns the Cell at a given set of coordinates. * * @param coordinates List of 0-based coordinates of the cell * * @return Cell * * @throws IndexOutOfBoundsException if coordinates are outside CellSet * bounds */ Cell getCell(List coordinates); /** * Returns the Cell at an ordinal. * *

Equivalent to * *

* getCell(ordinalToCoordinates(ordinal)) *
* * @param ordinal 0-based ordinal of the cell * * @return Cell * * @throws IndexOutOfBoundsException if ordinal lies outside CellSet bounds */ Cell getCell(int ordinal); /** * Returns the Cell at the intersection of a set of axis positions. * *

Equivalent to * *


     * getCell(
     *     Arrays.asList(
     *         positions[0].ordinal(),
     *         positions[1].ordinal() [, ...]))
     * 
* * @param positions Array of positions * * @return Cell * * @throws IllegalArgumentException if positions does not have the same * number of members as the cell set has axes * * @throws IndexOutOfBoundsException if positions lie outside CellSet * bounds */ Cell getCell(Position... positions); /** * 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. * * @param coordinates Cell coordinates * @return Cell ordinal */ int coordinatesToOrdinal(List coordinates); } // End CellSet.java olap4j-1.0.1.500/src/org/olap4j/transform/0000755000175000017500000000000011421322454017661 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/transform/MdxQueryTransform.java0000644000175000017500000000255711707255012024211 0ustar drazzibdrazzib/* // $Id: MdxQueryTransform.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.mdx.SelectNode; /** * MDX Query Transformation * *

General interface for transforming an MDX query to another one, * according to behavior and parameters encapsulated in implementing * classes * * @author etdub * @author jhyde * @version $Id: MdxQueryTransform.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jul 28, 2008 */ public interface MdxQueryTransform { String getName(); String getDescription(); SelectNode apply(SelectNode sn); } // End MdxQueryTransform.java olap4j-1.0.1.500/src/org/olap4j/transform/StandardTransformLibrary.java0000644000175000017500000000465511707255012025521 0ustar drazzibdrazzib/* // $Id: StandardTransformLibrary.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.Axis; import org.olap4j.CellSet; /** * Standard transformations library * * NOTE: is this really needed since transforms' ctors have the same * parameters as these functions? This serves only as a place to conveniently * regroup transforms in a "library". * * @author etdub * @author jhyde * @version $Id: StandardTransformLibrary.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jul 28, 2008 */ public class StandardTransformLibrary { public static MdxQueryTransform createDrillReplaceTransform( Axis axis, int positionOrdinalInAxis, int memberOrdinalInPosition, CellSet cellSet) { return new DrillReplaceTransform( axis, positionOrdinalInAxis, memberOrdinalInPosition, cellSet); } public static MdxQueryTransform createDrillDownOnPositionTransform( Axis axis, int positionOrdinalInAxis, int memberOrdinalInPosition, CellSet cellSet) { return new DrillDownOnPositionTransform( axis, positionOrdinalInAxis, memberOrdinalInPosition, cellSet); } public static MdxQueryTransform createRollUpLevelTransform( Axis axis, int positionOrdinalInAxis, int memberOrdinalInPosition, CellSet cellSet) { return new RollUpLevelTransform( axis, positionOrdinalInAxis, memberOrdinalInPosition, cellSet); } // many other transforms ... } // End StandardTransformLibrary.java olap4j-1.0.1.500/src/org/olap4j/transform/MdxHelper.java0000644000175000017500000000546011707255012022423 0ustar drazzibdrazzib/* // $Id: MdxHelper.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.mdx.*; import org.olap4j.metadata.Member; import java.util.ArrayList; import java.util.List; /** * Helper class for generating MDX expressions in query transforms. * *

Intentionally package-protected; this class is not to be used outside * this package. * * @author etdub * @version $Id: MdxHelper.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 7, 2008 */ class MdxHelper { public static MemberNode makeMemberNode(Member m) { return new MemberNode(null, m); } private static CallNode _makePropCallNode( ParseTreeNode node, String funcName) { List callArgs = new ArrayList(); callArgs.add(node); return new CallNode(null, funcName, Syntax.Property, callArgs); } public static CallNode makeChildrenCallNode(ParseTreeNode node) { return _makePropCallNode(node, "Children"); } public static CallNode makeParentCallNode(ParseTreeNode node) { return _makePropCallNode(node, "Parent"); } public static CallNode makeMembersCallNode(ParseTreeNode node) { return _makePropCallNode(node, "Members"); } public static CallNode makeLevelCallNode(ParseTreeNode node) { return _makePropCallNode(node, "Level"); } public static CallNode makeSetCallNode(List nodes) { return new CallNode(null, "{}", Syntax.Braces, nodes); } public static CallNode makeSetCallNode(ParseTreeNode... nodes) { List nodesList = new ArrayList(); for (ParseTreeNode n : nodes) { nodesList.add(n); } return makeSetCallNode(nodesList); } public static CallNode makeHierarchizeCallNode(ParseTreeNode node) { List callArgs = new ArrayList(); callArgs.add(node); return new CallNode(null, "Hierarchize", Syntax.Function, callArgs); } } // End MdxHelper.java olap4j-1.0.1.500/src/org/olap4j/transform/DrillDownOnPositionTransform.java0000644000175000017500000001341611707255012026347 0ustar drazzibdrazzib/* // $Id: DrillDownOnPositionTransform.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.*; import org.olap4j.mdx.*; import org.olap4j.metadata.Member; import java.util.List; /** * Drill down on position transform * * TODO: transform to be completed, not working for now. * *

Description: Adds the children of a member at a specific position on an * axis. The member to drill is identified from a CellSet with the axis, * positionOrdinalInAxis and memberOrdinalInPosition arguments. The drilled * member will still be present on the axis, in addition to its children. It * is recommended to apply a Hierarchize transform to the same axis of the * resulting query, in order to have members in correct hierarchical order. * *

Example of use: the user clicks on a member in a crosstab axis, in order * to see its children in addition to the member itself. * *

Applicability: this transform is applicable only to members in a query * that are drillable, i.e. non-leaf members. The CellSet resulting from the * execution of the initial MDX query must also be available. * * @author etdub * @author jhyde * @version $Id: DrillDownOnPositionTransform.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jul 30, 2008 */ public class DrillDownOnPositionTransform extends AxisTransform { // private final int positionOrdinalInAxis; // private final int memberOrdinalInPosition; // private final CellSet cellSet; private final Position positionToDrill; private final Member memberToDrill; private final List pathToMember; /** * ctor * * @param axis * @param positionOrdinalInAxis * @param memberOrdinalInPosition * @param cellSet */ public DrillDownOnPositionTransform( Axis axis, int positionOrdinalInAxis, int memberOrdinalInPosition, CellSet cellSet) { super(axis); // this.positionOrdinalInAxis = positionOrdinalInAxis; // this.memberOrdinalInPosition = memberOrdinalInPosition; // this.cellSet = cellSet; positionToDrill = TransformUtil.getPositionFromCellSet( axis, positionOrdinalInAxis, cellSet); memberToDrill = TransformUtil.getMemberFromCellSet( axis, positionOrdinalInAxis, memberOrdinalInPosition, cellSet); pathToMember = TransformUtil.getPathToMember( positionToDrill, memberOrdinalInPosition); } public String getName() { return "Drill down a member on a specific position"; } public String getDescription() { return "Expand a member on a position by adding its children"; } @Override protected ParseTreeNode processAxisExp(ParseTreeNode exp) { // TODO: implement me! return null; } // visitor for a tree of expressions inside a query axis // (not sure this should go here) class DrillDownOnPositionVisitor implements ParseTreeVisitor { public ParseTreeNode visit(SelectNode selectNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(AxisNode axis) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(WithMemberNode calcMemberNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(WithSetNode calcSetNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(CallNode call) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(IdentifierNode id) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(ParameterNode parameterNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(CubeNode cubeNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(DimensionNode dimensionNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(HierarchyNode hierarchyNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(LevelNode levelNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(MemberNode memberNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(LiteralNode literalNode) { // TODO Auto-generated method stub return null; } public ParseTreeNode visit(PropertyValueNode propertyValueNode) { // TODO Auto-generated method stub return null; } } } // End DrillDownOnPositionTransform.java olap4j-1.0.1.500/src/org/olap4j/transform/package.html0000644000175000017500000000031611421322454022142 0ustar drazzibdrazzib Provides services to transform MDX parse trees (experimental).

NOTE: This package is experimental. Classes may be renamed or removed in a future release of olap4j. olap4j-1.0.1.500/src/org/olap4j/transform/TransformUtil.java0000644000175000017500000000503711707255012023344 0ustar drazzibdrazzib/* // $Id: TransformUtil.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.*; import org.olap4j.metadata.Member; import java.util.ArrayList; import java.util.List; /** * Various helper functions for MDX query transforms. * *

This class is intentionally package-protected. It is NOT part of the * public olap4j API. * * @author etdub * @version $Id: TransformUtil.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 7, 2008 */ class TransformUtil { public static CellSetAxis getCellSetAxisFromCellSet( Axis axis, CellSet cellSet) { for (CellSetAxis a : cellSet.getAxes()) { if (a.getAxisOrdinal() == axis) { return a; } } // axis not found throw new IndexOutOfBoundsException(); } public static Position getPositionFromCellSet( Axis axis, int positionOrdinalInAxis, CellSet cellSet) { CellSetAxis a = getCellSetAxisFromCellSet(axis, cellSet); return a.getPositions().get(positionOrdinalInAxis); } public static Member getMemberFromCellSet( Axis axis, int positionOrdinalInAxis, int memberOrdinalInPosition, CellSet cellSet) { Position p = getPositionFromCellSet( axis, positionOrdinalInAxis, cellSet); return p.getMembers().get(memberOrdinalInPosition); } public static List getPathToMember( Position p, int memberOrdinalInPosition) { List pathToMember = new ArrayList(); for (int i = 0 ; i < memberOrdinalInPosition ; i++) { pathToMember.add(p.getMembers().get(i)); } return pathToMember; } } // End TransformUtil.java olap4j-1.0.1.500/src/org/olap4j/transform/RollUpLevelTransform.java0000644000175000017500000000712511707255012024634 0ustar drazzibdrazzib/* // $Id: RollUpLevelTransform.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.Axis; import org.olap4j.CellSet; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.Member; /** * Roll-up level transformation * *

Description: Replaces a member at a specific position on an axis by all * the members of its parent's level. The member to roll-up is identified from * a CellSet with the axis, positionOrdinalInAxis and memberOrdinalInPosition * arguments. * *

Example of use: the user clicks on a member in a crosstab axis, in order * to roll up to the members of the upper level. * *

Applicability: this transform is applicable only to members in a query * that are have a parent. (Note: how would this work in parent-child * hierarchies?) * * @author etdub * @version $Id: RollUpLevelTransform.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 4, 2008 */ public class RollUpLevelTransform extends AxisTransform { // private final int positionOrdinalInAxis; // private final int memberOrdinalInPosition; // private final CellSet cellSet; // private final Position positionToDrill; private final Member memberToDrill; // private final List pathToMember; /** * ctor * * @param axis * @param positionOrdinalInAxis * @param memberOrdinalInPosition * @param cellSet */ public RollUpLevelTransform( Axis axis, int positionOrdinalInAxis, int memberOrdinalInPosition, CellSet cellSet) { super(axis); // this.positionOrdinalInAxis = positionOrdinalInAxis; // this.memberOrdinalInPosition = memberOrdinalInPosition; // this.cellSet = cellSet; // Position positionToDrill = // TransformUtil.getPositionFromCellSet(axis, positionOrdinalInAxis, // cellSet); memberToDrill = TransformUtil.getMemberFromCellSet( axis, positionOrdinalInAxis, memberOrdinalInPosition, cellSet); // pathToMember = getPathToMember(positionToDrill, // memberOrdinalInPosition); } public String getName() { return "Roll member up a level"; } public String getDescription() { return "Replaces the member expression on the axis by all members " + "on its parent level"; } @Override protected ParseTreeNode processAxisExp(ParseTreeNode exp) { // FIXME: for now only 1 dimension on an axis is supported, // (naive implementation only used for proof of concept) return MdxHelper.makeSetCallNode( MdxHelper.makeMembersCallNode( MdxHelper.makeLevelCallNode( MdxHelper.makeParentCallNode( MdxHelper.makeMemberNode(memberToDrill))))); } } // End RollUpLevelTransform.java olap4j-1.0.1.500/src/org/olap4j/transform/TreeNode.java0000644000175000017500000001331011707255012022231 0ustar drazzibdrazzib/* // $Id: TreeNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import java.util.ArrayList; import java.util.List; /** * Generic Tree Node. * Adapted from JPivot (class com.tonbeller.jpivot.util.TreeNode) * *

REVIEW: Should this class be in the public olap4j API? (jhyde, 2008/8/14) * * @author etdub * @version $Id: TreeNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 7, 2008 */ class TreeNode { private TreeNode parent = null; private final List> children; private T reference; /** * Constructor. * * @param data the reference to hold in the node */ public TreeNode(T data) { this.reference = data; this.children = new ArrayList>(); } /** * Removes this node from the tree */ public void remove() { if (parent != null) { parent.removeChild(this); } } /** * Removes child node from the tree, if it exists * @param child node to remove */ public void removeChild(TreeNode child) { if (children.contains(child)) { children.remove(child); } } /** * Adds a child node to the tree * @param child node to be added */ public void addChildNode(TreeNode child) { child.parent = this; if (!children.contains(child)) { children.add(child); } } /** * Performs a deep copy (clone) of this node * The contained reference is not cloned but passed to the * new node. * @return the cloned TreeNode */ public TreeNode deepCopy() { TreeNode newNode = new TreeNode(reference); for (TreeNode child : children) { newNode.addChildNode(child.deepCopy()); } return newNode; } /** * Performs a deep copy (clone) of this node, pruning * all nodes below level specified by depth * @param depth number of child levels to be copied * @return the cloned TreeNode */ public TreeNode deepCopyPrune(int depth) { if (depth < 0) { throw new IllegalArgumentException("Depth is negative"); } TreeNode newNode = new TreeNode(reference); if (depth == 0) { return newNode; } for (TreeNode child : children) { newNode.addChildNode(child.deepCopyPrune(depth - 1)); } return newNode; } /** * Returns the level of this node, i.e. distance from * the root node * @return level distance from root node */ public int getLevel() { int level = 0; TreeNode p = parent; while (p != null) { ++level; p = p.parent; } return level; } /** * Gets a list of children nodes. * *

The list is mutable but shouldn't be modified by callers * (use the add and remove methods instead). * @return the list of children */ public List> getChildren() { return children; } /** * Gets the parent node. * @return parent node */ public TreeNode getParent() { return parent; } /** * Get the contained reference object * @return the reference object */ public T getReference() { return reference; } /** * Set the contained reference object * @param ref the new reference object */ public void setReference(T ref) { this.reference = ref; } /** * Walk through subtree of this node * @param callbackHandler callback function called on iteration * @return code used for navigation in the tree (@see TreeNodeCallback) */ public int walkTree(TreeNodeCallback callbackHandler) { int code = callbackHandler.handleTreeNode(this); if (code != TreeNodeCallback.CONTINUE) { return code; } for (TreeNode child : children) { code = child.walkTree(callbackHandler); if (code >= TreeNodeCallback.CONTINUE_PARENT) { return code; } } return code; } /** * Walk through children subtrees of this node * @param callbackHandler callback function called on iteration * @return code used for navigation in the tree (@see TreeNodeCallback) */ public int walkChildren(TreeNodeCallback callbackHandler) { int code = 0; for (TreeNode child : children) { code = callbackHandler.handleTreeNode(child); if (code >= TreeNodeCallback.CONTINUE_PARENT) { return code; } if (code == TreeNodeCallback.CONTINUE) { code = child.walkChildren(callbackHandler); if (code > TreeNodeCallback.CONTINUE_PARENT) { return code; } } } return code; } } // End TreeNode.java olap4j-1.0.1.500/src/org/olap4j/transform/DrillReplaceTransform.java0000644000175000017500000000741711707255012024775 0ustar drazzibdrazzib/* // $Id: DrillReplaceTransform.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.Axis; import org.olap4j.CellSet; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.Member; /** * Drill replace transformation * *

Description: Replaces a member at a specific position on an axis by its * children. The member to drill is identified from a CellSet with the axis, * positionOrdinalInAxis and memberOrdinalInPosition arguments. * *

Example of use: the user clicks on a member in a crosstab axis, in order * to see its children. * *

Applicability: this transform is applicable only to members in a query * that are drillable, i.e. non-leaf members. The CellSet resulting from the * execution of the initial MDX query must also be available. * * @author etdub * @version $Id: DrillReplaceTransform.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jul 30, 2008 */ public class DrillReplaceTransform extends AxisTransform { // private final int positionOrdinalInAxis; // private final int memberOrdinalInPosition; // private final CellSet cellSet; // private final Position positionToDrill; private final Member memberToDrill; // private final List pathToMember; /** * ctor * * @param axis axis (of the resulting CellSet) the member to be drilled * @param positionOrdinalInAxis position ordinal in axis of the member to * be drilled * @param memberOrdinalInPosition ordinal in position of the member to be * drilled * @param cellSet the CellSet resulting from execution of the query to be * transformed */ public DrillReplaceTransform( Axis axis, int positionOrdinalInAxis, int memberOrdinalInPosition, CellSet cellSet) { super(axis); // this.positionOrdinalInAxis = positionOrdinalInAxis; // this.memberOrdinalInPosition = memberOrdinalInPosition; // this.cellSet = cellSet; // Position positionToDrill = // TransformUtil.getPositionFromCellSet(axis, positionOrdinalInAxis, // cellSet); memberToDrill = TransformUtil.getMemberFromCellSet( axis, positionOrdinalInAxis, memberOrdinalInPosition, cellSet); // pathToMember = getPathToMember(positionToDrill, // memberOrdinalInPosition); } public String getName() { return "Drill Replace On Member"; } public String getDescription() { return "Drills and replace (by its children) a member on an axis"; } @Override protected ParseTreeNode processAxisExp(ParseTreeNode exp) { // FIXME: for now only 1 dimension on an axis is supported, // (naive implementation only used for proof of concept) return MdxHelper.makeSetCallNode( MdxHelper.makeChildrenCallNode( MdxHelper.makeMemberNode(memberToDrill))); } } // End DrillReplaceTransform.java olap4j-1.0.1.500/src/org/olap4j/transform/TreeNodeCallback.java0000644000175000017500000000341611707255012023654 0ustar drazzibdrazzib/* // $Id: TreeNodeCallback.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; /** * Handle callback for navigating in a tree of TreeNode * * Adapted from JPivot (interface com.tonbeller.jpivot.util.TreeNodeCallback) * *

REVIEW: Should this class be in the public olap4j API? (jhyde, 2008/8/14) * * @author etdub * @version $Id: TreeNodeCallback.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 7, 2008 */ interface TreeNodeCallback { public static final int CONTINUE = 0; public static final int CONTINUE_SIBLING = 1; public static final int CONTINUE_PARENT = 2; public static final int BREAK = 3; /** * Callback function. * * @param node the current node to handle * @return CONTINUE (0) : continue tree walk * CONTINUE_SIBLING (1) : continue to the sibling * CONTINUE_PARENT (2) : continue at parent level * BREAK (3) : break tree walk */ int handleTreeNode(TreeNode node); } // End TreeNodeCallback.java olap4j-1.0.1.500/src/org/olap4j/transform/AxisTransform.java0000644000175000017500000000421011707255012023323 0ustar drazzibdrazzib/* // $Id: AxisTransform.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.Axis; import org.olap4j.mdx.*; /** * Abstract representation of an MDX query transform acting on * a single query axis (e.g. drill-down on member, roll-up, ...) * * @author etdub * @version $Id: AxisTransform.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 7, 2008 * */ public abstract class AxisTransform implements MdxQueryTransform { protected final Axis axis; protected AxisTransform(Axis axis) { this.axis = axis; } public SelectNode apply(SelectNode sn) { // do a deep copy of the existing query SelectNode before // modifying it: SelectNode newSelectNode = sn.deepCopy(); for (AxisNode an : newSelectNode.getAxisList()) { if (an.getAxis() == axis) { // this is the axis we're drilling ParseTreeNode initialAxisExp = an.getExpression(); // apply the drill operation ParseTreeNode newAxisExp = processAxisExp(initialAxisExp); // replace the expression in the axis by the new generated one an.setExpression(newAxisExp); } } return newSelectNode; } protected abstract ParseTreeNode processAxisExp(ParseTreeNode axisExp); } // End AxisTransform.java olap4j-1.0.1.500/src/org/olap4j/transform/Quax.java0000644000175000017500000000352411707255012021450 0ustar drazzibdrazzib/* // $Id: Quax.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.transform; import org.olap4j.CellSetAxis; import org.olap4j.Position; import org.olap4j.metadata.Member; /** * Representation of member expressions on a query axis, derived from * CellSetAxis objects. * *

Quaxes are used by MDX axis query transforms, to construct and use * an internal tree-like representation of positions and members from the * result CellSetAxis objects of a previous MDX query. This is needed * for OLAP navigation operators like drill-down on a position. * *

Inspired from the JPivot Quax class. * *

NOTE: not exactly sure how to implement this, to be completed... * * @author etdub * @version $Id: Quax.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 7, 2008 */ public class Quax { private final CellSetAxis cellSetAxis; private TreeNode memberTree; public Quax(CellSetAxis cellSetAxis) { this.cellSetAxis = cellSetAxis; for (Position p : cellSetAxis.getPositions()) { p.getMembers(); } } } // End Quax.java olap4j-1.0.1.500/src/org/olap4j/type/0000755000175000017500000000000011540707142016632 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/type/LevelType.java0000644000175000017500000000667211707254774021436 0ustar drazzibdrazzib/* // $Id: LevelType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.OlapException; import org.olap4j.metadata.*; /** * The type of an expression which represents a level. * * @author jhyde * @since Feb 17, 2005 * @version $Id: LevelType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class LevelType implements Type { private final Dimension dimension; private final Hierarchy hierarchy; private final Level level; private final String digest; /** * Creates a type representing a level. * * @param dimension Dimension which values of this type must belong to, or * null if not known * * @param hierarchy Hierarchy which values of this type must belong to, or * null if not known * * @param level Level which values of this type must belong to, or null if * not known */ public LevelType( Dimension dimension, Hierarchy hierarchy, Level level) { this.dimension = dimension; this.hierarchy = hierarchy; this.level = level; if (level != null) { assert hierarchy != null : "hierarchy != null"; assert level.getHierarchy() == hierarchy : "level.getHierarchy() == hierarchy"; } if (hierarchy != null) { assert dimension != null : "dimension != null"; assert hierarchy.getDimension() == dimension : "hierarchy.getDimension() == dimension"; } StringBuilder buf = new StringBuilder("LevelType<"); if (level != null) { buf.append("level=").append(level.getUniqueName()); } else if (hierarchy != null) { buf.append("hierarchy=").append(hierarchy.getUniqueName()); } else if (dimension != null) { buf.append("dimension=").append(dimension.getUniqueName()); } buf.append(">"); this.digest = buf.toString(); } // not part of public olap4j API private static LevelType forType(Type type) throws OlapException { return new LevelType( type.getDimension(), type.getHierarchy(), type.getLevel()); } public boolean usesDimension(Dimension dimension, boolean maybe) { if (this.dimension == null) { return maybe; } else { return this.dimension.equals(dimension); } } public Dimension getDimension() { return dimension; } public Hierarchy getHierarchy() { return hierarchy; } public Level getLevel() { return level; } public String toString() { return digest; } } // End LevelType.java olap4j-1.0.1.500/src/org/olap4j/type/StringType.java0000644000175000017500000000222011707254774021616 0ustar drazzibdrazzib/* // $Id: StringType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; /** * The type of a string expression. * * @author jhyde * @since Feb 17, 2005 * @version $Id: StringType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class StringType extends ScalarType { /** * Creates a string type. */ public StringType() { } } // End StringType.java olap4j-1.0.1.500/src/org/olap4j/type/NullType.java0000644000175000017500000000227611707254774021275 0ustar drazzibdrazzib/* // $Id: NullType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; /** * The type of a null expression. * * @author medstat * @version $Id: NullType.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 21, 2006 */ public class NullType extends ScalarType { /** * Creates a null type. */ public NullType() { } public String toString() { return "NULL"; } } // End NullType.java olap4j-1.0.1.500/src/org/olap4j/type/package.html0000644000175000017500000000010011421322444021076 0ustar drazzibdrazzib Type system for MDX expressions. olap4j-1.0.1.500/src/org/olap4j/type/BooleanType.java0000644000175000017500000000256211707254774021740 0ustar drazzibdrazzib/* // $Id: BooleanType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; /** * The type of a boolean (logical) expression. * *

An example of a boolean expression is the predicate * *

* [Measures].[Unit Sales] > 1000 *
* * @author jhyde * @since Feb 17, 2005 * @version $Id: BooleanType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class BooleanType extends ScalarType { /** * Creates a boolean type. */ public BooleanType() { } public String toString() { return "BOOLEAN"; } } // End BooleanType.java olap4j-1.0.1.500/src/org/olap4j/type/SetType.java0000644000175000017500000000435211707254774021113 0ustar drazzibdrazzib/* // $Id: SetType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.metadata.*; /** * Set type. * * @author jhyde * @since Feb 17, 2005 * @version $Id: SetType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class SetType implements Type { private final Type elementType; /** * Creates a type representing a set of elements of a given type. * * @param elementType The type of the elements in the set, or null if not * known */ public SetType(Type elementType) { assert elementType instanceof MemberType || elementType instanceof TupleType; this.elementType = elementType; } /** * Returns the type of the elements of this set. * * @return element type */ public Type getElementType() { return elementType; } public boolean usesDimension(Dimension dimension, boolean maybe) { if (elementType == null) { return maybe; } return elementType.usesDimension(dimension, maybe); } public Dimension getDimension() { return elementType == null ? null : elementType.getDimension(); } public Hierarchy getHierarchy() { return elementType == null ? null : elementType.getHierarchy(); } public Level getLevel() { return elementType == null ? null : elementType.getLevel(); } } // End SetType.java olap4j-1.0.1.500/src/org/olap4j/type/MemberType.java0000644000175000017500000001043411707254774021565 0ustar drazzibdrazzib/* // $Id: MemberType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.OlapException; import org.olap4j.metadata.*; /** * The type of an expression which represents a member. * * @author jhyde * @since Feb 17, 2005 * @version $Id: MemberType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class MemberType implements Type { private final Hierarchy hierarchy; private final Dimension dimension; private final Level level; private final Member member; private final String digest; // not part of public olap4j public API private static final MemberType Unknown = new MemberType(null, null, null, null); /** * Creates a type representing a member. * * @param dimension Dimension the member belongs to, or null if not known. * * @param hierarchy Hierarchy the member belongs to, or null if not known. * * @param level Level the member belongs to, or null if not known * * @param member The precise member, or null if not known */ public MemberType( Dimension dimension, Hierarchy hierarchy, Level level, Member member) { this.dimension = dimension; this.hierarchy = hierarchy; this.level = level; this.member = member; if (member != null) { assert level != null; assert member.getLevel().equals(level); } if (level != null) { assert hierarchy != null; assert level.getHierarchy().equals(hierarchy); } if (hierarchy != null) { assert dimension != null; assert hierarchy.getDimension().equals(dimension); } StringBuilder buf = new StringBuilder("MemberType<"); if (member != null) { buf.append("member=").append(member.getUniqueName()); } else if (level != null) { buf.append("level=").append(level.getUniqueName()); } else if (hierarchy != null) { buf.append("hierarchy=").append(hierarchy.getUniqueName()); } else if (dimension != null) { buf.append("dimension=").append(dimension.getUniqueName()); } buf.append(">"); this.digest = buf.toString(); } public String toString() { return digest; } public Hierarchy getHierarchy() { return hierarchy; } public Level getLevel() { return level; } /** * Returns the member of this type, or null if not known. * * @return member of this type */ public Member getMember() { return member; } public boolean usesDimension(Dimension dimension, boolean maybe) { if (this.dimension == null) { return maybe; } else { return this.dimension.equals(dimension); } } // not part of public olap4j API Type getValueType() { // todo: when members have more type information (double vs. integer // vs. string), return better type if member != null. return new ScalarType(); } public Dimension getDimension() { return dimension; } // not part of public olap4j API static MemberType forType(Type type) throws OlapException { if (type instanceof MemberType) { return (MemberType) type; } else { return new MemberType( type.getDimension(), type.getHierarchy(), type.getLevel(), null); } } } // End MemberType.java olap4j-1.0.1.500/src/org/olap4j/type/DimensionType.java0000644000175000017500000000460511707254774022306 0ustar drazzibdrazzib/* // $Id: DimensionType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.metadata.*; /** * The type of an expression which represents a Dimension. * * @author jhyde * @since Feb 17, 2005 * @version $Id: DimensionType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class DimensionType implements Type { private final Dimension dimension; private final String digest; public static final DimensionType Unknown = new DimensionType(null); /** * Creates a type representing a dimension. * * @param dimension Dimension which values of this type must belong to, or * null if not known */ public DimensionType(Dimension dimension) { this.dimension = dimension; StringBuilder buf = new StringBuilder("DimensionType<"); if (dimension != null) { buf.append("dimension=").append(dimension.getUniqueName()); } buf.append(">"); this.digest = buf.toString(); } public boolean usesDimension(Dimension dimension, boolean maybe) { if (this.dimension == null) { return maybe; } else { return this.dimension.equals(dimension); } } public Hierarchy getHierarchy() { return dimension == null ? null : dimension.getHierarchies().size() > 1 ? null : dimension.getHierarchies().get(0); } public Level getLevel() { return null; } public Dimension getDimension() { return dimension; } public String toString() { return digest; } } // End DimensionType.java olap4j-1.0.1.500/src/org/olap4j/type/SymbolType.java0000644000175000017500000000360111707254774021621 0ustar drazzibdrazzib/* // $Id: SymbolType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; /** * The type of a symbolic expression. * *

Symbols are identifiers which occur in particular function calls, * generally to indicate an option for how the function should be executed. * They are similar to an enumerated type in other * languages. * *

For example, the optional 3rd argument to the Order function * can be one of the symbols ASC, DESC, * BASC, BDESC. The signature of the * Order function is therefore * *

* Order(<Set>, <Scalar expression> [, <Symbol>]) *
* * and * *
* Order([Store].Members, [Measures].[Unit Sales], BDESC) *
* * would be a valid call to the function. * * @author jhyde * @since Feb 17, 2005 * @version $Id: SymbolType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class SymbolType extends ScalarType { /** * Creates a symbol type. */ public SymbolType() { } } // End SymbolType.java olap4j-1.0.1.500/src/org/olap4j/type/TypeUtil.java0000644000175000017500000001321511707254774021273 0ustar drazzibdrazzib/* // $Id: TypeUtil.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.OlapException; import org.olap4j.metadata.Hierarchy; /** * Utility methods relating to types. * *

NOTE: This class is experimental. Not part of the public olap4j API. * * @author jhyde * @since Feb 17, 2005 * @version $Id: TypeUtil.java 482 2012-01-05 23:27:27Z jhyde $ */ public class TypeUtil { /** * Given a set type, returns the element type. Or its element type, if it * is a set type. And so on. */ private static Type stripSetType(Type type) { while (type instanceof SetType) { type = ((SetType) type).getElementType(); } return type; } /** * Converts a type to a member or tuple type. * If it cannot, returns null. */ private static Type toMemberOrTupleType(Type type) throws OlapException { type = stripSetType(type); if (type instanceof TupleType) { return (TupleType) type; } else { return toMemberType(type); } } /** * Converts a type to a member type. * If it is a set, strips the set. * If it is a member type, returns the type unchanged. * If it is a dimension, hierarchy or level type, converts it to * a member type. * If it is a tuple, number, string, or boolean, returns null. */ static MemberType toMemberType(Type type) throws OlapException { type = stripSetType(type); if (type instanceof MemberType) { return (MemberType) type; } else if (type instanceof DimensionType || type instanceof HierarchyType || type instanceof LevelType) { return MemberType.forType(type); } else { return null; } } /** * Returns whether this type is union-compatible with another. * In general, to be union-compatible, types must have the same * dimensionality. * * @param type1 First type * @param type2 Second type * @return Whether types are union-compatible * @throws OlapException on error */ static boolean isUnionCompatible( Type type1, Type type2) throws OlapException { if (type1 instanceof TupleType) { return type2 instanceof TupleType && ((TupleType) type1).isUnionCompatibleWith( (TupleType) type2); } else { final MemberType memberType1 = toMemberType(type1); if (memberType1 == null) { return false; } final MemberType memberType2 = toMemberType(type2); if (memberType2 == null) { return false; } final Hierarchy hierarchy1 = memberType1.getHierarchy(); final Hierarchy hierarchy2 = memberType2.getHierarchy(); return equal(hierarchy1, hierarchy2); } } private static boolean equal( final Hierarchy hierarchy1, final Hierarchy hierarchy2) { if (hierarchy1 == null || hierarchy2 == null || hierarchy2.getUniqueName().equals( hierarchy1.getUniqueName())) { // They are compatible. return true; } else { return false; } } /** * Returns whether a value of a given type can be evaluated to a scalar * value. * *

The rules are as follows:

    *
  • Clearly boolean, numeric and string expressions can be evaluated. *
  • Member and tuple expressions can be interpreted as a scalar value. * The expression is evaluated to establish the context where a measure * can be evaluated. *
  • Hierarchy and dimension expressions are implicitly * converted into the current member, and evaluated as above. *
  • Level expressions cannot be evaluated *
  • Cube and Set (even sets with a single member) cannot be evaluated. *
* * @param type Type * @return Whether an expression of this type can be evaluated to yield a * scalar value. */ public static boolean canEvaluate(Type type) { return ! (type instanceof SetType || type instanceof CubeType || type instanceof LevelType); } /** * Returns whether a type is a set type. * * @param type Type * @return Whether a value of this type can be evaluated to yield a set. */ public static boolean isSet(Type type) { return type instanceof SetType; } private static boolean couldBeMember(Type type) { return type instanceof MemberType || type instanceof HierarchyType || type instanceof DimensionType; } static boolean equal(Object o, Object p) { return o == null ? p == null : p != null && o.equals(p); } } // End TypeUtil.java olap4j-1.0.1.500/src/org/olap4j/type/TupleType.java0000644000175000017500000000646011707254774021453 0ustar drazzibdrazzib/* // $Id: TupleType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.OlapException; import org.olap4j.metadata.*; /** * Tuple type. * * @author jhyde * @since Feb 17, 2005 * @version $Id: TupleType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class TupleType implements Type { final Type[] elementTypes; private final String digest; /** * Creates a type representing a tuple whose fields are the given types. * * @param elementTypes Array of field types */ public TupleType(Type[] elementTypes) { assert elementTypes != null; this.elementTypes = elementTypes.clone(); final StringBuilder buf = new StringBuilder("TupleType<"); for (int i = 0; i < elementTypes.length; i++) { Type elementType = elementTypes[i]; if (i > 0) { buf.append(", "); } buf.append(elementType.toString()); } buf.append(">"); digest = buf.toString(); } public String toString() { return digest; } public boolean usesDimension(Dimension dimension, boolean maybe) { for (Type elementType : elementTypes) { if (elementType.usesDimension(dimension, maybe)) { return true; } } return false; } public Dimension getDimension() { return null; } public Hierarchy getHierarchy() { return null; } public Level getLevel() { return null; } // not part of public olap4j API private Type getValueType() throws OlapException { for (Type elementType : elementTypes) { if (elementType instanceof MemberType) { MemberType memberType = (MemberType) elementType; if (memberType.getDimension().getDimensionType() == Dimension.Type.MEASURE) { return memberType.getValueType(); } } } return new ScalarType(); } // not part of public olap4j API boolean isUnionCompatibleWith(TupleType that) throws OlapException { if (this.elementTypes.length != that.elementTypes.length) { return false; } for (int i = 0; i < this.elementTypes.length; i++) { if (!TypeUtil.isUnionCompatible( this.elementTypes[i], that.elementTypes[i])) { return false; } } return true; } } // End TupleType.java olap4j-1.0.1.500/src/org/olap4j/type/NumericType.java0000644000175000017500000000232611707254774021761 0ustar drazzibdrazzib/* // $Id: NumericType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; /** * The type of a numeric expression. * * @author jhyde * @since Feb 17, 2005 * @version $Id: NumericType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class NumericType extends ScalarType { /** * Creates a numeric type. */ public NumericType() { } public String toString() { return "NUMERIC"; } } // End NumericType.java olap4j-1.0.1.500/src/org/olap4j/type/Type.java0000644000175000017500000000524011707254774020434 0ustar drazzibdrazzib/* // $Id: Type.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.metadata.*; /** * Type of an MDX expression. * *

All type objects are immutable. * * @author jhyde * @since Feb 17, 2005 * @version $Id: Type.java 482 2012-01-05 23:27:27Z jhyde $ */ public interface Type { /** * Returns whether this type contains a given dimension.

* * For example: *

    *
  • DimensionType([Gender]) uses only the * [Gender] dimension.
  • *
  • TupleType(MemberType([Gender]), MemberType([Store])) * uses [Gender] and [Store] * dimensions.
  • *

* * The maybe parameter comes into play when the * dimensional information is incomplete. For example, when applied to * TupleType(MemberType(null), MemberType([Store])), * usesDimension([Gender], false) returns true because it * is possible that the expression returns a member of the * [Gender] dimension. * * @param dimension Dimension * @param maybe If true, returns true only if this type definitely * uses the dimension * * @return whether this type definitely (or if maybe is true, * possibly) uses the given dimension */ boolean usesDimension(Dimension dimension, boolean maybe); /** * Returns the dimension of this type, or null if not known. * * @return dimension of this type */ Dimension getDimension(); /** * Returns the hierarchy of this type. If not applicable, throws. * * @return hierarchy of this type */ Hierarchy getHierarchy(); /** * Returns the level of this type, or null if not known. * * @return level of this type */ Level getLevel(); } // End Type.java olap4j-1.0.1.500/src/org/olap4j/type/DecimalType.java0000644000175000017500000000526011707254774021715 0ustar drazzibdrazzib/* // $Id: DecimalType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; /** * Subclass of {@link NumericType} which guarantees fixed number of decimal * places. In particular, a decimal with zero scale is an integer. * * @author jhyde * @since May 3, 2005 * @version $Id: DecimalType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class DecimalType extends NumericType { private final int precision; private final int scale; /** * Creates a decimal type with precision and scale. * *

Examples:

    *
  • 123.45 has precision 5, scale 2. *
  • 12,345,000 has precision 5, scale -3. *
* *

The largest value is 10 ^ (precision - scale). Hence the largest * DECIMAL(5, -3) value is 10 ^ 8. * * @param precision Maximum number of decimal digits which a value of * this type can have. * Must be greater than zero. * Use {@link Integer#MAX_VALUE} if the precision is unbounded. * @param scale Number of digits to the right of the decimal point. */ public DecimalType(int precision, int scale) { super(); assert precision > 0 : "expected precision > 0"; this.precision = precision; this.scale = scale; } /** * Returns the maximum number of decimal digits which a value of * this type can have. * * @return maximum precision allowed for values of this type */ public int getPrecision() { return precision; } /** * Returns the number of digits to the right of the decimal point. * * @return number of digits to the right of the decimal point */ public int getScale() { return scale; } public String toString() { return precision == Integer.MAX_VALUE ? "DECIMAL(" + scale + ")" : "DECIMAL(" + precision + ", " + scale + ")"; } } // End DecimalType.java olap4j-1.0.1.500/src/org/olap4j/type/ScalarType.java0000644000175000017500000000312011707254774021555 0ustar drazzibdrazzib/* // $Id: ScalarType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.metadata.*; /** * Base class for types which represent scalar values. * *

An instance of this class means a scalar value of unknown type. * Usually one of the derived classes {@link NumericType}, * {@link StringType}, {@link BooleanType} is used instead. * * @author jhyde * @since Feb 17, 2005 * @version $Id: ScalarType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class ScalarType implements Type { public boolean usesDimension(Dimension dimension, boolean maybe) { return false; } public Hierarchy getHierarchy() { return null; } public Level getLevel() { return null; } public Dimension getDimension() { return null; } } // End ScalarType.java olap4j-1.0.1.500/src/org/olap4j/type/HierarchyType.java0000644000175000017500000000534311707254774022277 0ustar drazzibdrazzib/* // $Id: HierarchyType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.OlapException; import org.olap4j.metadata.*; /** * The type of an expression which represents a hierarchy. * * @author jhyde * @since Feb 17, 2005 * @version $Id: HierarchyType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class HierarchyType implements Type { private final Dimension dimension; private final Hierarchy hierarchy; private final String digest; /** * Creates a type representing a hierarchy. * * @param dimension Dimension which values of this type must belong to, or * null if not known * * @param hierarchy Hierarchy which values of this type must belong to, or * null if not known */ public HierarchyType( Dimension dimension, Hierarchy hierarchy) { this.dimension = dimension; this.hierarchy = hierarchy; StringBuilder buf = new StringBuilder("HierarchyType<"); if (hierarchy != null) { buf.append("hierarchy=").append(hierarchy.getUniqueName()); } else if (dimension != null) { buf.append("dimension=").append(dimension.getUniqueName()); } buf.append(">"); this.digest = buf.toString(); } // not part of public olap4j API private static HierarchyType forType(Type type) throws OlapException { return new HierarchyType(type.getDimension(), type.getHierarchy()); } public boolean usesDimension(Dimension dimension, boolean maybe) { if (this.dimension == null) { return maybe; } else { return this.dimension.equals(dimension); } } public Dimension getDimension() { return dimension; } public Hierarchy getHierarchy() { return hierarchy; } public Level getLevel() { return null; } public String toString() { return digest; } } // End HierarchyType.java olap4j-1.0.1.500/src/org/olap4j/type/CubeType.java0000644000175000017500000000405711707254774021240 0ustar drazzibdrazzib/* // $Id: CubeType.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.type; import org.olap4j.metadata.*; /** * The type of an expression which represents a Cube or Virtual Cube. * * @author jhyde * @since Feb 17, 2005 * @version $Id: CubeType.java 482 2012-01-05 23:27:27Z jhyde $ */ public class CubeType implements Type { private final Cube cube; /** * Creates a type representing a cube. * * @param cube Cube */ public CubeType(Cube cube) { this.cube = cube; } /** * Returns the cube. * * @return the cube */ public Cube getCube() { return cube; } public boolean usesDimension(Dimension dimension, boolean maybe) { return false; } public Dimension getDimension() { return null; } public Hierarchy getHierarchy() { return null; } public Level getLevel() { return null; } public boolean equals(Object obj) { if (obj instanceof CubeType) { CubeType that = (CubeType) obj; return TypeUtil.equal(this.cube, that.cube); } else { return false; } } public int hashCode() { return cube == null ? 0 : cube.hashCode(); } } // End CubeType.java olap4j-1.0.1.500/src/org/olap4j/OlapConnection.java0000644000175000017500000004731111707255012021434 0ustar drazzibdrazzib/* // $Id: OlapConnection.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.mdx.parser.MdxParserFactory; import org.olap4j.metadata.*; import java.sql.*; import java.util.List; import java.util.Locale; /** * Connection to an OLAP server. * *

OlapConnection is a subclass of {@link Connection}. It can be pooled * by a connection pooling framework or obtained directly via the Java * standard {@link DriverManager}. The JDBC URL prefix of olap connections * is dependent of the driver implementation. Such implementations are, * among others possible: * *

  • Olap4j's XML/A driver
  • Mondrian
* *

Olap connections have a different metadata hierarchy than regular * JDBC. The connection's metadata is available using * {@link OlapConnection#getMetaData()}, and returns a specialized subclass * of {@link DatabaseMetaData}. The objects at the root of the hierarchy * are {@link Database} class objects. * *

A connection needs be bound to a database, a catalog and a schema. * Implementations are expected to automatically discover these if no * driver specific parameters indicated which ones to use. * * @author jhyde * @version $Id: OlapConnection.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface OlapConnection extends Connection, OlapWrapper { // overrides Connection, with refined return type and throws list /** * {@inheritDoc} * @throws OlapException if database error occurs */ OlapDatabaseMetaData getMetaData() throws OlapException; /** * Creates a prepared OLAP Statement. * *

This method is the equivalent, for OLAP, of the * {@link Connection#prepareStatement(String)} JDBC method.

* * @param mdx MDX query string * @return prepared statement * @throws OlapException if database error occurs */ PreparedOlapStatement prepareOlapStatement(String mdx) throws OlapException; /** * Returns the factory used to create MDX parsers in this connection. * * @return MDX parser factory */ MdxParserFactory getParserFactory(); // overrides Connection, with refined return type and throws list /** * {@inheritDoc} * @throws OlapException if database error occurs */ OlapStatement createStatement() throws OlapException; /** * Returns the database name currently active for this connection. If no * database name was specified either through the JDBC URL or through * {@link OlapConnection#setDatabase(String)}, the driver will select the * first one available. * * @return The name of the database currently active for this connection. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *
    *
  • A server error occurs.
  • *
  • No databases exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
*/ String getDatabase() throws OlapException; /** * Sets the name of the database that will be used for this connection. * Overrides the value passed, if any, through the JDBC URL. * * @param databaseName * The name of the database to use. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *
    *
  • A server error occurs.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
*/ void setDatabase(String databaseName) throws OlapException; /** * Returns the current active {@link org.olap4j.metadata.Database} of this * connection. * *

If the user has not specified a database name to use for this * connection, the driver will auto-select the first Database available. * * @see #setDatabase(String) * @see #getOlapDatabases() * @return The currently active Database, or null of none are currently * selected. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *

    *
  • A server error occurs.
  • *
  • No databases exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
*/ Database getOlapDatabase() throws OlapException; /** * Returns a list of {@link org.olap4j.metadata.Database} objects which * belong to this connection's OLAP server. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @return List of Database objects in this connection's OLAP server * @throws OlapException if a database access error occurs */ NamedList getOlapDatabases() throws OlapException; /** * Returns the {@link Catalog} name which is currently active for this * connection. * *

* If the user has not specified a database name to use for this * connection, the driver will automatically select the first one * available. If the user has not specified a catalog name to use, * the driver will also use the first one available on the server. * * @return The name of the catalog which is active for this connection. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *

    *
  • A server error occurs.
  • *
  • No database name was specified and no databases exist * on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
  • No catalog names were specified and no catalogs * exist on the server.
  • *
  • The user specified a catalog name which does not exist * on the server.
  • *
*/ String getCatalog() throws OlapException; /** * Sets the name of the catalog that will be used for this connection. * Overrides the value passed, if any, through the JDBC URL. * * @param catalogName * The name of the catalog to use for this connection. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *
    *
  • A server error occurs.
  • *
  • No database name was specified and no databases * exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
  • The user specified a catalog name which does not exist * on the server.
  • *
*/ void setCatalog(String catalogName) throws OlapException; /** * Returns the current active {@link org.olap4j.metadata.Catalog} * of this connection. * *

If the user has not selected a Database and Catalog to use for * this connection, the driver will auto-select the first * Database and Catalog available on the server. * *

Any auto-discovery performed by implementations must take into * account the specified database name and catalog name, if any. * * @return The currently active catalog, or null of none are * currently selected. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *

    *
  • A server error occurs.
  • *
  • No database name was specified and no databases * exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
  • No catalog name was specified and no catalogs * exist on the server.
  • *
  • The user specified a catalog name which does not exist * on the server.
  • *
*/ Catalog getOlapCatalog() throws OlapException; /** * Returns a list of {@link org.olap4j.metadata.Catalog} objects which * belong to this connection's OLAP server. * *

If the user has not selected a Database to use for * this connection, the implementation auto-selects * the first Database available. Any auto-discovery performed * by implementations must take into account the connection * Database parameter. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined. * * @return List of Catalogs in this connection's OLAP server * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *

    *
  • A server error occurs.
  • *
  • No database name was specified and no databases * exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
*/ NamedList getOlapCatalogs() throws OlapException; /** * Returns the {@link Schema} name that was selected for this connection, * either through the JDBC URL or via * {@link #setSchema(String)}. * *

If the user has not selected a Database, Catalog and Schema to use * for this connection, the driver will auto-select the first Database, * Catalog and Schema available. * *

Any auto-discovery performed by implementations must take into * account the specified Database, Catalog and Schema names, if any. * * @return The name of the schema currently selected for this connection. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *

    *
  • A server error occurs.
  • *
  • No database name was specified and no databases * exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
  • No catalog name was specified and no catalogs * exist on the server.
  • *
  • The user specified a catalog name which does not exist * on the server.
  • *
  • No schema name was specified and no schema * exist on the server.
  • *
  • The user specified a schema name which does not exist * on the server.
  • *
*/ String getSchema() throws OlapException; /** * Sets the name of the active schema for this connection. * Overrides the value passed, if any, through the JDBC URL. * * @param schemaName The name of the schema to use for this connection. * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *
    *
  • A server error occurs.
  • *
  • No database name was specified and no databases * exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
  • No catalog name was specified and no catalogs * exist on the server.
  • *
  • The user specified a catalog name which does not exist * on the server.
  • *
  • No schema name was specified and no schema * exist on the server.
  • *
  • The user specified a schema name which does not exist * on the server.
  • *
*/ void setSchema(String schemaName) throws OlapException; /** * Returns the current active {@link org.olap4j.metadata.Schema} * of this connection. * *

If the user has not selected a Database, Catalog and Schema to use * for this connection, the driver will auto-select the first Database, * Catalog and Schema available. * *

Any auto-discovery performed by implementations must take into * account the specified Database, Catalog and Schema names, if any. * * @return The currently active schema * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *

    *
  • A server error occurs.
  • *
  • No database name was specified and no databases * exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
  • No catalog name was specified and no catalogs * exist on the server.
  • *
  • The user specified a catalog name which does not exist * on the server.
  • *
  • No schema name was specified and no schema * exist on the server.
  • *
  • The user specified a schema name which does not exist * on the server.
  • *
*/ Schema getOlapSchema() throws OlapException; /** * Returns a list of {@link org.olap4j.metadata.Schema} objects which * belong to this connection's OLAP server. * *

If the user has not selected a Database, Catalog and Schema to use * for this connection, the driver will auto-select the first Database and * Catalog available. * *

Any auto-discovery performed by implementations must take into * account the specified Database, Catalog and Schema names, if any. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined. * * @return List of Catalogs in this connection's OLAP server * @throws OlapException * An exception will be thrown, if any of these conditions * are true: *

    *
  • A server error occurs.
  • *
  • No database name was specified and no databases * exist on the server.
  • *
  • The user specified a database name which does not * exist on the server.
  • *
  • No catalog name was specified and no catalogs * exist on the server.
  • *
  • The user specified a catalog name which does not exist * on the server.
  • *
  • No schema name was specified and no schema * exist on the server.
  • *
  • The user specified a schema name which does not exist * on the server.
  • *
*/ NamedList getOlapSchemas() throws OlapException; /** * Sets the current locale of this connection. The value must not be null. * *

If the locale is not set, the JDK's current locale is used (see * {@link java.util.Locale#getDefault()}). * *

Most drivers support a Locale connect-string property. * * @param locale Locale * * @see #getLocale() */ void setLocale(Locale locale); /** * Returns this connection's locale. The value is never null. * * @return locale of this connection * * @see #setLocale(java.util.Locale) * @see org.olap4j.metadata.MetadataElement#getCaption() * @see org.olap4j.metadata.MetadataElement#getDescription() */ Locale getLocale(); /** * Sets the name of the role in which this connection executes queries. If * the name of the role is null, the connection reverts to the default * access control context. * * @param roleName Name of role * @throws OlapException if role name is invalid */ void setRoleName(String roleName) throws OlapException; /** * Returns the name of the role in which this connection executes queries. * * @return name of the role in which this connection executes queries */ String getRoleName(); /** * Returns a list of the names of roles that are available for this user to * execute queries. * * @return a list of role names, or null if the available roles are not * known * * @throws OlapException if database error occurs */ List getAvailableRoleNames() throws OlapException; /** * Creates a Scenario. * *

It does not become the active scenario for the current connection. * To do this, call {@link #setScenario(Scenario)}. * * @see #setScenario * * @return a new Scenario * * @throws OlapException if database error occurs */ Scenario createScenario() throws OlapException; /** * Sets the active Scenario of this connection. * *

After setting a scenario, the client may call * {@link Cell#setValue} to change the value of cells returned * from queries. The value of those cells is changed. This operation is * referred to as 'writeback', and is used to perform 'what if' analysis, * such as budgeting. See {@link Scenario} for more details. * *

If {@code scenario} is null, the connection will have no active * scenario, and writeback is not allowed. * *

Scenarios are created using {@link #createScenario()}. * * @param scenario Scenario * * @throws OlapException if database error occurs */ void setScenario(Scenario scenario) throws OlapException; /** * Returns this connection's active Scenario, or null if there is no * active Scenario. * * @return Active scenario, or null * * @throws OlapException if database error occurs */ Scenario getScenario() throws OlapException; } // End OlapConnection.java olap4j-1.0.1.500/src/org/olap4j/metadata/0000755000175000017500000000000011651266446017443 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/metadata/Property.java0000644000175000017500000007122311707254772022140 0ustar drazzibdrazzib/* // $Id: Property.java 485 2012-01-17 06:57:57Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.impl.Olap4jUtil; import java.util.Collections; import java.util.Set; /** * Definition of a property of a {@link Member} or * {@link org.olap4j.Cell}. * * @author jhyde * @version $Id: Property.java 485 2012-01-17 06:57:57Z jhyde $ * @since Aug 23, 2006 */ public interface Property extends MetadataElement { /** * Returns the datatype of this Property. * * @return datatype of this Property */ Datatype getDatatype(); /** * Returns a set of flags which describe the type of this Property. * * @return type of this Property */ Set getType(); /** * Returns the content type of this Property. * * @return content type */ ContentType getContentType(); /** * Enumeration of aspects of the type of a Property. In particular, whether * it belongs to a member or a cell. * *

The values are as specified by XMLA for the PROPERTY_TYPE attribute * of the MDSCHEMA_PROPERTIES data set. * For example, XMLA specifies that the value 9 (0x1 | 0x8) means that a * property belongs to a member and is a binary large object (BLOB). * In this case, {@link Property#getType} will return the {@link Set} * {{@link #MEMBER}, {@link #BLOB}}. */ enum TypeFlag implements XmlaConstant { /** * Identifies a property of a member. This property can be used in the * DIMENSION PROPERTIES clause of the SELECT statement. */ MEMBER(1), /** * Identifies a property of a cell. This property can be used in the * CELL PROPERTIES clause that occurs at the end of the SELECT * statement. */ CELL(2), /** * Identifies an internal property. */ SYSTEM(4), /** * Identifies a property which contains a binary large object (blob). */ BLOB(8); private final int xmlaOrdinal; public static final Set CELL_TYPE_FLAG = Collections.unmodifiableSet( Olap4jUtil.enumSetOf(TypeFlag.CELL)); public static final Set MEMBER_TYPE_FLAG = Collections.unmodifiableSet( Olap4jUtil.enumSetOf(TypeFlag.MEMBER)); private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(TypeFlag.class); private TypeFlag(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MDPROP_" + name(); } public String getDescription() { return null; } public int xmlaOrdinal() { return xmlaOrdinal; } /** * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } } /** * Enumeration of the system properties available for every {@link Member}. * *

The following properties are mandatory for members:

    *
  • {@link #CATALOG_NAME}
  • *
  • {@link #SCHEMA_NAME}
  • *
  • {@link #CUBE_NAME}
  • *
  • {@link #DIMENSION_UNIQUE_NAME}
  • *
  • {@link #HIERARCHY_UNIQUE_NAME}
  • *
  • {@link #LEVEL_UNIQUE_NAME}
  • *
  • {@link #LEVEL_NUMBER}
  • *
  • {@link #MEMBER_UNIQUE_NAME}
  • *
  • {@link #MEMBER_NAME}
  • *
  • {@link #MEMBER_TYPE}
  • *
  • {@link #MEMBER_GUID}
  • *
  • {@link #MEMBER_CAPTION}
  • *
  • {@link #MEMBER_ORDINAL}
  • *
  • {@link #CHILDREN_CARDINALITY}
  • *
  • {@link #PARENT_LEVEL}
  • *
  • {@link #PARENT_UNIQUE_NAME}
  • *
  • {@link #PARENT_COUNT}
  • *
  • {@link #DESCRIPTION}
  • *
*/ enum StandardMemberProperty implements Property { /** * Definition of the property which * holds the name of the current catalog. */ CATALOG_NAME( Datatype.STRING, 10, false, null, "Optional. The name of the catalog to which this member belongs. " + "NULL if the provider does not support catalogs."), /** * Definition of the property which * holds the name of the current schema. */ SCHEMA_NAME( Datatype.STRING, 11, false, null, "Optional. The name of the schema to which this member belongs. " + "NULL if the provider does not support schemas."), /** * Definition of the property which * holds the name of the current cube. */ CUBE_NAME( Datatype.STRING, 12, false, null, "Required. Name of the cube to which this member belongs."), /** * Definition of the property which * holds the unique name of the current dimension. */ DIMENSION_UNIQUE_NAME( Datatype.STRING, 13, false, null, "Required. Unique name of the dimension to which this member " + "belongs. For providers that generate unique names by " + "qualification, each component of this name is delimited."), /** * Definition of the property which * holds the unique name of the current hierarchy. */ HIERARCHY_UNIQUE_NAME( Datatype.STRING, 14, false, null, "Required. Unique name of the hierarchy. If the member belongs to " + "more than one hierarchy, there is one row for each hierarchy " + "to which it belongs. For providers that generate unique names " + "by qualification, each component of this name is delimited."), /** * Definition of the property which * holds the unique name of the current level. */ LEVEL_UNIQUE_NAME( Datatype.STRING, 15, false, null, "Required. Unique name of the level to which the member belongs. " + "For providers that generate unique names by qualification, " + "each component of this name is delimited."), /** * Definition of the property which * holds the ordinal of the current level. */ LEVEL_NUMBER( Datatype.UNSIGNED_INTEGER, 16, false, null, "Required. The distance of the member from the root of the " + "hierarchy. The root level is zero."), /** * Definition of the property which * holds the ordinal of the current member. */ MEMBER_ORDINAL( Datatype.UNSIGNED_INTEGER, 17, false, null, "Required. Ordinal number of the member. Sort rank of the member " + "when members of this dimension are sorted in their natural " + "sort order. If providers do not have the concept of natural " + "ordering, this should be the rank when sorted by MEMBER_NAME."), /** * Definition of the property which * holds the name of the current member. */ MEMBER_NAME( Datatype.STRING, 18, false, null, "Required. Name of the member."), /** * Definition of the property which * holds the unique name of the current member. */ MEMBER_UNIQUE_NAME( Datatype.STRING, 19, false, null, "Required. Unique name of the member. For providers that generate " + "unique names by qualification, each component of this name is " + "delimited."), /** * Definition of the property which * holds the type of the member. */ MEMBER_TYPE( Datatype.STRING, 20, false, null, "Required. Type of the member. Can be one of the following values: " + "MDMEMBER_Datatype.TYPE_REGULAR, MDMEMBER_Datatype.TYPE_ALL, " + "MDMEMBER_Datatype.TYPE_FORMULA, MDMEMBER_Datatype.TYPE_MEASURE, " + "MDMEMBER_Datatype.TYPE_UNKNOWN. MDMEMBER_Datatype.TYPE_FORMULA " + "takes precedence over MDMEMBER_Datatype.TYPE_MEASURE. " + "Therefore, if there is a formula (calculated) member on the " + "Measures dimension, it is listed as " + "MDMEMBER_Datatype.TYPE_FORMULA."), /** * Definition of the property which * holds the GUID of the member */ MEMBER_GUID( Datatype.STRING, 21, false, null, "Optional. Member GUID. NULL if no GUID exists."), /** * Definition of the property which * holds the label or caption associated with the member, or the * member's name if no caption is defined. */ MEMBER_CAPTION( Datatype.STRING, 22, false, null, "Required. A label or caption associated with the member. Used " + "primarily for display purposes. If a caption does not exist, " + "MEMBER_NAME is returned."), /** * Definition of the property which holds the * number of children this member has. */ CHILDREN_CARDINALITY( Datatype.UNSIGNED_INTEGER, 23, false, null, "Required. Number of children that the member has. This can be an " + "estimate, so consumers should not rely on this to be the exact " + "count. Providers should return the best estimate possible."), /** * Definition of the property which holds the * distance from the root of the hierarchy of this member's parent. */ PARENT_LEVEL( Datatype.UNSIGNED_INTEGER, 24, false, null, "Required. The distance of the member's parent from the root level " + "of the hierarchy. The root level is zero."), /** * Definition of the property which holds the * Name of the current catalog. */ PARENT_UNIQUE_NAME( Datatype.STRING, 25, false, null, "Required. Unique name of the member's parent. NULL is returned " + "for any members at the root level. For providers that generate " + "unique names by qualification, each component of this name is " + "delimited."), /** * Definition of the property which holds the * number of parents that this member has. Generally 1, or 0 * for root members. */ PARENT_COUNT( Datatype.UNSIGNED_INTEGER, 26, false, null, "Required. Number of parents that this member has."), /** * Definition of the property which holds the * description of this member. */ DESCRIPTION( Datatype.STRING, 27, false, null, "Optional. A human-readable description of the member."), /** * Definition of the internal property which holds the * name of the system property which determines whether to show a member * (especially a measure or calculated member) in a user interface such * as JPivot. */ $visible( Datatype.BOOLEAN, 28, true, null, null), /** * Definition of the internal property which holds the * value of the member key in the original data type. MEMBER_KEY is for * backward-compatibility. MEMBER_KEY has the same value as KEY0 for * non-composite keys, and MEMBER_KEY property is null for composite * keys. */ MEMBER_KEY( Datatype.VARIANT, 29, true, null, "Optional. The value of the member key. Null for composite keys."), /** * Definition of the boolean property that indicates whether * a member is a placeholder member for an empty position in a * dimension hierarchy. */ IS_PLACEHOLDERMEMBER( Datatype.BOOLEAN, 30, false, null, "Required. Whether the member is a placeholder member for an empty " + "position in a dimension hierarchy."), /** * Definition of the property that indicates whether the member is a * data member. */ IS_DATAMEMBER( Datatype.BOOLEAN, 31, false, null, "Required. whether the member is a data member"), /** * Definition of the property which * holds the level depth of a member. * *

Caution: Level depth of members in parent-child hierarchy isn't * from their levels. It's calculated from the underlying data * dynamically. */ DEPTH( Datatype.UNSIGNED_INTEGER, 43, true, null, "The level depth of a member"), /** * Definition of the property which * holds the DISPLAY_INFO required by XML/A. * *

Caution: This property's value is calculated based on a specified * MDX query, so its value is dynamic at runtime. */ DISPLAY_INFO( Datatype.UNSIGNED_INTEGER, 44, false, null, "Display instruction of a member for XML/A"), /** * Definition of the property which * holds the value of a cell. Is usually numeric (since most measures * are numeric) but is occasionally another type. */ VALUE( Datatype.VARIANT, 41, false, null, "The unformatted value of the cell."); private final Datatype type; private final String description; private final boolean internal; private StandardMemberProperty( Datatype type, int ordinal, boolean internal, Class enumClazz, String description) { // assert ordinal == ordinal(); this.internal = internal; this.type = type; this.description = description; } public String getName() { return name(); } public String getUniqueName() { return name(); } public String getCaption() { // NOTE: This caption will be the same in all locales, since // StandardMemberProperty has no way of deducing the current // connection. Providers that wish to localize the caption of // built-in properties should create a wrapper around // StandardMemberProperty that is aware of the current connection or // locale. return name(); } public String getDescription() { // NOTE: This description will be the same in all locales, since // StandardMemberProperty has no way of deducing the current // connection. Providers that wish to localize the description of // built-in properties should create a wrapper around // StandardCellProperty that is aware of the current connection or // locale. return description; } public Datatype getDatatype() { return type; } public Set getType() { return TypeFlag.MEMBER_TYPE_FLAG; } public ContentType getContentType() { return ContentType.REGULAR; } public boolean isInternal() { return internal; } public boolean isVisible() { return !internal; } } /** * Enumeration of the system properties available for every * {@link org.olap4j.Cell}. * *

The following propertiess are mandatory for cells:

    *
  • {@link #BACK_COLOR}
  • *
  • {@link #CELL_EVALUATION_LIST}
  • *
  • {@link #CELL_ORDINAL}
  • *
  • {@link #FORE_COLOR}
  • *
  • {@link #FONT_NAME}
  • *
  • {@link #FONT_SIZE}
  • *
  • {@link #FONT_FLAGS}
  • *
  • {@link #FORMAT_STRING}
  • *
  • {@link #FORMATTED_VALUE}
  • *
  • {@link #NON_EMPTY_BEHAVIOR}
  • *
  • {@link #SOLVE_ORDER}
  • *
  • {@link #VALUE}
  • *
*/ enum StandardCellProperty implements Property { BACK_COLOR( Datatype.STRING, 30, false, null, "The background color for displaying the VALUE or FORMATTED_VALUE " + "property. For more information, see FORE_COLOR and BACK_COLOR " + "Contents."), CELL_EVALUATION_LIST( Datatype.STRING, 31, false, null, "The semicolon-delimited list of evaluated formulas applicable to " + "the cell, in order from lowest to highest solve order. For more " + "information about solve order, see Understanding Pass Order and " + "Solve Order"), CELL_ORDINAL( Datatype.UNSIGNED_INTEGER, 32, false, null, "The ordinal number of the cell in the dataset."), FORE_COLOR( Datatype.STRING, 33, false, null, "The foreground color for displaying the VALUE or FORMATTED_VALUE " + "property. For more information, see FORE_COLOR and BACK_COLOR " + "Contents."), FONT_NAME( Datatype.STRING, 34, false, null, "The font to be used to display the VALUE or FORMATTED_VALUE " + "property."), FONT_SIZE( Datatype.STRING, 35, false, null, "Font size to be used to display the VALUE or FORMATTED_VALUE " + "property."), FONT_FLAGS( Datatype.UNSIGNED_INTEGER, 36, false, XmlaConstants.FontFlag.class, "The bitmask detailing effects on the font. The value is the " + "result of a bitwise OR operation of one or more of the " + "following constants: MDFF_BOLD = 1, MDFF_ITALIC = 2, " + "MDFF_UNDERLINE = 4, MDFF_STRIKEOUT = 8. For example, the value " + "5 represents the combination of bold (MDFF_BOLD) and underline " + "(MDFF_UNDERLINE) font effects."), /** * Definition of the property which * holds the formatted value of a cell. */ FORMATTED_VALUE( Datatype.STRING, 37, false, null, "The character string that represents a formatted display of the " + "VALUE property."), /** * Definition of the property which * holds the format string used to format cell values. */ FORMAT_STRING( Datatype.STRING, 38, false, null, "The format string used to create the FORMATTED_VALUE property " + "value. For more information, see FORMAT_STRING Contents."), NON_EMPTY_BEHAVIOR( Datatype.STRING, 39, false, null, "The measure used to determine the behavior of calculated members " + "when resolving empty cells."), /** * Definition of the property which * determines the solve order of a calculated member with respect to * other calculated members. */ SOLVE_ORDER( Datatype.INTEGER, 40, false, null, "The solve order of the cell."), /** * Definition of the property which * holds the value of a cell. Is usually numeric (since most measures * are numeric) but is occasionally another type. */ VALUE( Datatype.VARIANT, 41, false, null, "The unformatted value of the cell."), /** * Definition of the property which * holds the datatype of a cell. Valid values are "String", * "Numeric", "Integer". The property's value derives from the * "datatype" attribute of the "Measure" element; if the * datatype attribute is not specified, the datatype is * "Numeric" by default, except measures whose aggregator is * "Count", whose datatype is "Integer". */ DATATYPE( Datatype.STRING, 42, false, null, "The datatype of the cell."), LANGUAGE( Datatype.UNSIGNED_INTEGER, 0, false, null, "The locale where the FORMAT_STRING will be applied. LANGUAGE is " + "usually used for currency conversion."), ACTION_TYPE( Datatype.INT4, 0, false, XmlaConstants.ActionType.class, "A bitmask that indicates which types of actions exist on the " + "cell."), UPDATEABLE( Datatype.UNSIGNED_INTEGER, 0, false, XmlaConstants.Updateable.class, "A value that indicates whether the cell can be updated."); /** * The datatype of the property. */ private final Datatype type; private final String description; private final boolean internal; private StandardCellProperty( Datatype type, int ordinal, boolean internal, Class enumClazz, String description) { this.type = type; this.internal = internal; this.description = description; } public Datatype getDatatype() { return type; } public Set getType() { return TypeFlag.CELL_TYPE_FLAG; } public String getName() { return name(); } public String getUniqueName() { return name(); } public String getCaption() { // NOTE: This caption will be the same in all locales, since // StandardCellProperty has no way of deducing the current // connection. Providers that wish to localize the caption of // built-in properties should create a wrapper around // StandardCellProperty that is aware of the current connection or // locale. return name(); } public String getDescription() { // NOTE: This description will be the same in all locales, since // StandardCellProperty has no way of deducing the current // connection. Providers that wish to localize the description of // built-in properties should create a wrapper around // StandardCellProperty that is aware of the current connection or // locale. return description; } public boolean isInternal() { return internal; } public boolean isVisible() { return !internal; } public ContentType getContentType() { return ContentType.REGULAR; } } /** * Enumeration of the types of a Property. * *

The values are as specified by XMLA. * For example, XMLA specifies MD_PROPTYPE_CAPTION with ordinal 0x21, * which corresponds to the value {@link #CAPTION}, * whose {@link #xmlaOrdinal} is 0x21. */ enum ContentType implements XmlaConstant { REGULAR(0x00), ID(0x01), RELATION_TO_PARENT(0x02), ROLLUP_OPERATOR(0x03), ORG_TITLE(0x11), CAPTION(0x21), CAPTION_SHORT(0x22), CAPTION_DESCRIPTION(0x23), CAPTION_ABREVIATION(0x24), WEB_URL(0x31), WEB_HTML(0x32), WEB_XML_OR_XSL(0x33), WEB_MAIL_ALIAS(0x34), ADDRESS(0x41), ADDRESS_STREET(0x42), ADDRESS_HOUSE(0x43), ADDRESS_CITY(0x44), ADDRESS_STATE_OR_PROVINCE(0x45), ADDRESS_ZIP(0x46), ADDRESS_QUARTER(0x47), ADDRESS_COUNTRY(0x48), ADDRESS_BUILDING(0x49), ADDRESS_ROOM(0x4A), ADDRESS_FLOOR(0x4B), ADDRESS_FAX(0x4C), ADDRESS_PHONE(0x4D), GEO_CENTROID_X(0x61), GEO_CENTROID_Y(0x62), GEO_CENTROID_Z(0x63), GEO_BOUNDARY_TOP(0x64), GEO_BOUNDARY_LEFT(0x65), GEO_BOUNDARY_BOTTOM(0x66), GEO_BOUNDARY_RIGHT(0x67), GEO_BOUNDARY_FRONT(0x68), GEO_BOUNDARY_REAR(0x69), GEO_BOUNDARY_POLYGON(0x6A), PHYSICAL_SIZE(0x71), PHYSICAL_COLOR(0x72), PHYSICAL_WEIGHT(0x73), PHYSICAL_HEIGHT(0x74), PHYSICAL_WIDTH(0x75), PHYSICAL_DEPTH(0x76), PHYSICAL_VOLUME(0x77), PHYSICAL_DENSITY(0x78), PERSON_FULL_NAME(0x82), PERSON_FIRST_NAME(0x83), PERSON_LAST_NAME(0x84), PERSON_MIDDLE_NAME(0x85), PERSON_DEMOGRAPHIC(0x86), PERSON_CONTACT(0x87), QTY_RANGE_LOW(0x91), QTY_RANGE_HIGH(0x92), FORMATTING_COLOR(0xA1), FORMATTING_ORDER(0xA2), FORMATTING_FONT(0xA3), FORMATTING_FONT_EFFECTS(0xA4), FORMATTING_FONT_SIZE(0xA5), FORMATTING_SUB_TOTAL(0xA6), DATE(0xB1), DATE_START(0xB2), DATE_ENDED(0xB3), DATE_CANCELED(0xB4), DATE_MODIFIED(0xB5), DATE_DURATION(0xB6), VERSION(0xC1); private final int xmlaOrdinal; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(ContentType.class); private ContentType(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MD_PROPTYPE_" + name(); } public String getDescription() { return null; } public int xmlaOrdinal() { return xmlaOrdinal; } /** * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } } } // End Property.java olap4j-1.0.1.500/src/org/olap4j/metadata/NamedSet.java0000644000175000017500000000273511707254772022016 0ustar drazzibdrazzib/* // $Id: NamedSet.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.mdx.ParseTreeNode; /** * Metadata object describing a named set defined against a {@link Cube}. * * @author jhyde * @version $Id: NamedSet.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 24, 2006 */ public interface NamedSet extends MetadataElement { /** * Returns the Cube that this NamedSet belongs * to. * * @return cube this named set belongs to */ Cube getCube(); /** * Returns the expression which gives the value of this NamedSet. * * @return expression */ ParseTreeNode getExpression(); } // End NamedSet.java olap4j-1.0.1.500/src/org/olap4j/metadata/MetadataElement.java0000644000175000017500000000756211707254772023353 0ustar drazzibdrazzib/* // $Id: MetadataElement.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; /** * An element which describes the structure of an OLAP schema. * * @author jhyde * @version $Id: MetadataElement.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 13, 2006 */ public interface MetadataElement { /** * Returns the name of this element. * *

Name is never null. Unlike {@link #getCaption() caption} and * {@link #getDescription() description}, an element's name is the same in * every {@link java.util.Locale}. * * @return name of this element */ String getName(); /** * Returns the unique name of this element within its schema. * *

The unique name is never null, and is unique among all elements in * this {@link Schema}. * *

Unlike {@link #getCaption() caption} and * {@link #getDescription() description}, an element's unique name is the * same in every {@link java.util.Locale}. * *

The structure of the unique name is provider-specific and subject to * change between provider versions. Applications should not attempt to * reverse-engineer the structure of the name. * * @return unique name of this element */ String getUniqueName(); /** * Returns the caption of this element in the current connection's * {@link java.util.Locale}. * *

This method may return the empty string, but never returns null. * The rules for deriving an element's caption are provider-specific, * but generally if no caption is defined for the element in a given locale, * returns the name of the element.

* * @return caption of this element in the current locale; never null. * * @see org.olap4j.OlapConnection#getLocale() */ String getCaption(); /** * Returns the description of this element in the current connection's * {@link java.util.Locale}. * *

This method may return the empty string, but never returns null. * The rules for deriving an element's description are provider-specific, * but generally if no description is defined * for the element in a given locale, returns the description in base * locale.

* * @return description of this element in the current locale; never null. * * @see org.olap4j.OlapConnection#getLocale() */ String getDescription(); /** * Returns whether this element is visible to end-users. * *

Visibility is a hint for client applications. An element's visibility * does not affect how it is treated when MDX queries are evaluated. * *

If you wish to hide an MDX element at a deeper level, consider two * OLAP concepts that sound similar to visibility but have different * semantics: * *

    *
  • {@link Member#isHidden Hidden members} in ragged hierarchies;
  • *
  • {@link org.olap4j.OlapConnection#getRoleName Access control}
  • *
* * @return Whether this element is visible */ boolean isVisible(); } // End MetadataElement.java olap4j-1.0.1.500/src/org/olap4j/metadata/package.html0000644000175000017500000000212711421322444021710 0ustar drazzibdrazzib Provides classes and interfaces for browsing an OLAP schema.

Schemas have a hierarchical structure:

  • {@link org.olap4j.OlapConnection}
    • {@link org.olap4j.metadata.Catalog}
      • {@link org.olap4j.metadata.Schema}
        • {@link org.olap4j.metadata.Cube}
          • {@link org.olap4j.metadata.Dimension}
            • {@link org.olap4j.metadata.Hierarchy}
              • {@link org.olap4j.metadata.Level}
                • {@link org.olap4j.metadata.Member}
                • {@link org.olap4j.metadata.Property}
          • {@link org.olap4j.metadata.NamedSet}
        • Dimension (shared)

olap4j-1.0.1.500/src/org/olap4j/metadata/Cube.java0000644000175000017500000002047511707254772021175 0ustar drazzibdrazzib/* // $Id: Cube.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.OlapException; import org.olap4j.mdx.IdentifierSegment; import java.util.*; /** * Central metadata object for representation of multidimensional data. * *

A Cube belongs to a {@link Schema}, and is described by a list of * {@link Dimension}s and a list of {@link Measure}s. It may also have one or * more {@link NamedSet}s. * * @see org.olap4j.metadata.Cube#getMeasures() * * @author jhyde * @version $Id: Cube.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface Cube extends MetadataElement { /** * Returns the {@link Schema} this Cube belongs to. * * @return Schema this Cube belongs to */ Schema getSchema(); /** * Returns a list of {@link Dimension} objects in this Cube. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getDimensions(String,String,String,String) * * @return list of Dimensions */ NamedList getDimensions(); /** * Returns a list of {@link Hierarchy} objects in this Cube. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getHierarchies(String, String, String, String, String) * * @return list of Dimensions */ NamedList getHierarchies(); /** * Returns a list of {@link Measure} objects in this Cube. * *

The list includes both stored and calculated members, and (unlike * the {@link org.olap4j.OlapDatabaseMetaData#getMeasures} method or the * MDSCHEMA_MEASURES XMLA request) is sorted by ordinal. * * @see org.olap4j.OlapDatabaseMetaData#getMeasures(String,String,String,String,String) * * @return list of Measures */ List getMeasures(); /** * Returns a list of {@link NamedSet} objects in this Cube. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getSets(String,String,String,String) * * @return list of NamedSets */ NamedList getSets(); /** * 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(); /** * Finds a member in the current Cube based upon its fully-qualified name. * Returns the member, or null if there is no member with this name. * *

The fully-qualified name starts with the name of the dimension, * followed by the name of a root member, and continues with the name of * each successive member on the path from the root member. If a member's * name is unique within its level, preceding member name can be omitted. * *

For example, {@code "[Product].[Food]"} and * {@code "[Product].[All Products].[Food]"} * are both valid ways to locate the "Food" member of the "Product" * dimension. * *

The name is represented as a list of {@link IdentifierSegment} * objects. There are some common ways to create such a list. If you have an * identifier, call * {@link org.olap4j.mdx.IdentifierNode#parseIdentifier(String)} * to parse the string into an identifier, then * {@link org.olap4j.mdx.IdentifierNode#getSegmentList()}. For example, * *

Member member = cube.lookupMember(
*   IdentifierNode.parseIdentifier( * "[Product].[Food]").getSegmentList())
* *

If you have an array of names, call * {@link org.olap4j.mdx.IdentifierNode#ofNames(String...)}. For example, * *

Member member = cube.lookupMember(
*   IdentifierNode.parseIdentifier( * "[Product].[Food]").getSegmentList())
* * @param nameParts Components of the fully-qualified member name * * @return member with the given name, or null if not found * * @throws OlapException if error occurs */ Member lookupMember(List nameParts) throws OlapException; /** * Finds a collection of members in the current Cube related to a given * member. * *

The method first looks up a member with the given fully-qualified * name as for {@link #lookupMember(java.util.List)}, then applies the set * of tree-operations to find related members. * *

The returned collection is sorted by level number then by member * ordinal. If no member is found with the given name, the collection is * empty. * *

For example, * *

     * lookupMembers(
     *     EnumSet.of(TreeOp.ANCESTORS, TreeOp.CHILDREN),
     *     "Time", "1997", "Q2")
     * 
* * returns * *

     * [Time].[1997]
     * [Time].[1997].[Q2].[4]
     * [Time].[1997].[Q2].[5]
     * [Time].[1997].[Q2].[6]
     * 
* *

The fully-qualified name starts with the name of the dimension, * followed by the name of a root member, and continues with the name of * each successive member on the path from the root member. If a member's * name is unique within its level, preceding member name can be omitted. * *

For example, * lookupMember("Product", "Food") * and * lookupMember("Product", "All Products", "Food") * are both valid ways to locate the "Food" member of the "Product" * dimension. * * @param nameParts Components of the fully-qualified member name * * @param treeOps Collection of tree operations to travel relative to * given member in order to create list of members * * @return collection of members related to the given member, or empty * set if the member is not found * * @throws OlapException if error occurs */ List lookupMembers( Set treeOps, List nameParts) throws OlapException; /** * Tells whether or not drill through operations are * possible in this cube. * @return True if drillthrough is enabled, false otherwise. */ boolean isDrillThroughEnabled(); } // End Cube.java olap4j-1.0.1.500/src/org/olap4j/metadata/XmlaConstant.java0000644000175000017500000001407111707254772022725 0ustar drazzibdrazzib/* // $Id: XmlaConstant.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import java.util.List; import java.util.Set; /** * Enumerated value that belongs to a set of constants in the XML for Analysis * (XMLA) specification. * *

Every {@code enum} E that implements this interface also has a method to * get the {@link org.olap4j.metadata.XmlaConstant.Dictionary} of all its values: * *

public static Dictionary<E> getDictionary();
* *

Here is a collection of enum classes and the prefix used to generate * their XMLA constant names. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
PrefixEnum class
DBTYPE_{@link Datatype}
MD_DIMTYPE_{@link org.olap4j.metadata.Dimension.Type}
MDLEVEL_TYPE_{@link org.olap4j.metadata.Level.Type}
MDMEASURE_AGG_{@link org.olap4j.metadata.Measure.Aggregator}
MDTREEOP_{@link org.olap4j.metadata.Member.TreeOp}
MD_PROPTYPE_{@link org.olap4j.metadata.Property.ContentType}
MDPROP_{@link org.olap4j.metadata.Property.TypeFlag}
none{@link org.olap4j.metadata.XmlaConstants.Access}
MDACTION_TYPE_{@link org.olap4j.metadata.XmlaConstants.ActionType}
none{@link org.olap4j.metadata.XmlaConstants.AuthenticationMode}
none{@link org.olap4j.metadata.XmlaConstants.AxisFormat}
DBTYPE_{@link org.olap4j.metadata.XmlaConstants.DBType}
MDFF_{@link org.olap4j.metadata.XmlaConstants.FontFlag}
none{@link org.olap4j.metadata.XmlaConstants.Format}
DBLITERAL_{@link org.olap4j.metadata.XmlaConstants.Literal}
none{@link org.olap4j.metadata.XmlaConstants.Method}
none{@link org.olap4j.metadata.XmlaConstants.ProviderType}
none{@link org.olap4j.metadata.XmlaConstants.Updateable}
DBPROPVAL_VISUAL_MODE_{@link org.olap4j.metadata.XmlaConstants.VisualMode}
* * @author jhyde * @version $Id: XmlaConstant.java 482 2012-01-05 23:27:27Z jhyde $ */ public interface XmlaConstant { /** * Returns the name of this constant as specified by XMLA. * *

Often the name is an enumeration-specific prefix plus the name of * the Java enum constant. For example, * {@link org.olap4j.metadata.Dimension.Type} has * prefix "MD_DIMTYPE_", and therefore this method returns * "MD_DIMTYPE_PRODUCTS" for the enum constant * {@link org.olap4j.metadata.Dimension.Type#PRODUCTS}. * * @return ordinal code as specified by XMLA. */ String xmlaName(); /** * Returns the description of this constant. * * @return Description of this constant. */ String getDescription(); /** * Returns the code of this constant as specified by XMLA. * *

For example, the XMLA specification says that the ordinal of * MD_DIMTYPE_PRODUCTS is 8, and therefore this method returns 8 * for {@link org.olap4j.metadata.Dimension.Type#PRODUCTS}. * * @return ordinal code as specified by XMLA. */ int xmlaOrdinal(); interface Dictionary & XmlaConstant> { /** * Returns the enumeration value with the given ordinal in the XMLA * specification, or null if there is no such. * * @param xmlaOrdinal XMLA ordinal * @return Enumeration value */ E forOrdinal(int xmlaOrdinal); /** * Returns the enumeration value with the given name in the XMLA * specification, or null if there is no such. * * @param xmlaName XMLA name * @return Enumeration value */ E forName(String xmlaName); /** * Creates a set of values by parsing a mask. * * @param xmlaOrdinalMask Bit mask * @return Set of E values */ Set forMask(int xmlaOrdinalMask); /** * Converts a set of enum values to an integer by logical OR-ing their * codes. * * @param set Set of enum values * @return Bitmap representing set of enum values */ int toMask(Set set); /** * Returns all values of the enum. * *

This method may be more efficient than * {@link Class#getEnumConstants()} because the latter is required to * create a new array every call to prevent corruption. * * @return List of enum values */ List getValues(); /** * Returns the class that the enum values belong to. * * @return enum class */ Class getEnumClass(); } } // End XmlaConstant.java olap4j-1.0.1.500/src/org/olap4j/metadata/Dimension.java0000644000175000017500000001053611707254772022241 0ustar drazzibdrazzib/* // $Id: Dimension.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.OlapException; /** * An organized hierarchy of categories, known as levels, that describes data * in a cube. * *

A Dimension typically describes a similar set of members upon which the * user wants to base an analysis. * *

A Dimension must have at least one Hierarchy, and may have more than one, * but most have exactly one Hierarchy.

* * @author jhyde * @version $Id: Dimension.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface Dimension extends MetadataElement { /** * Returns the hierarchies in this Dimension. * *

Many dimensions have only one Hierarchy, whose name is the same as the * Dimension. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getHierarchies * * @return hierarchies in this dimension */ NamedList getHierarchies(); /** * Returns the type of this Dimension. * * @return dimension type * * @throws OlapException if database error occurs */ Dimension.Type getDimensionType() throws OlapException; /** * Returns the default Hierarchy of this Dimension. * * @return default hierarchy */ Hierarchy getDefaultHierarchy(); /** * Enumeration of the types of a Dimension. * *

Some of the values are as specified by XMLA. * For example, XMLA specifies MD_DIMTYPE_PRODUCTS with ordinal 8, * which corresponds to the value {@link #PRODUCTS}, * whose {@link #xmlaOrdinal} is 8. * * @see Level.Type * @see Member.Type * @see Dimension#getDimensionType */ public enum Type implements XmlaConstant { /** * Indicates that the dimension is not related to time. */ UNKNOWN(0), /** * Indicates that a dimension is a time dimension. */ TIME(1), /** * Indicates that a dimension is the Measures dimension. */ MEASURE(2), OTHER(3), QUANTITATIVE(5), ACCOUNTS(6), CUSTOMERS(7), PRODUCTS(8), SCENARIO(9), UTILITY(10), CURRENCY(11), RATES(12), CHANNEL(13), PROMOTION(14), ORGANIZATION(15), BILL_OF_MATERIALS(16), GEOGRAPHY(17); private final int xmlaOrdinal; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(Type.class); /** * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } /** * Creates a Dimension Type. * * @param xmlaOrdinal Ordinal code as specified by XMLA */ private Type(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MD_DIMTYPE_" + name(); } public String getDescription() { return ""; } public int xmlaOrdinal() { return xmlaOrdinal; } } } // End Dimension.java olap4j-1.0.1.500/src/org/olap4j/metadata/Database.java0000644000175000017500000001710711707254772022021 0ustar drazzibdrazzib/* // $Id: Database.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.OlapConnection; import org.olap4j.OlapException; import java.util.List; /** * Highest level element in the hierarchy of metadata objects. * *

A Database contains one or more {@link Catalog}s.

* *

To obtain the collection of databases in the current server, call the * {@link OlapConnection#getOlapDatabases()} method. To obtain the current * active catalog object, to which a connection is bound, use * {@link OlapConnection#getOlapDatabase()}. * *

The hierarchy of metadata objects, rooted at the connection from which * they are accessed, is as follows: *

*
    *
  • {@link org.olap4j.OlapConnection}
      *
    • {@link Database}
        *
      • {@link Catalog}
          *
        • {@link Schema}
            *
          • {@link Cube}
              *
            • {@link Dimension}
                *
              • {@link Hierarchy}
                  *
                • {@link Level}
                    *
                  • {@link Member}
                  • *
                  • {@link Property}
                  • *
                • *
              • *
            • *
            • {@link NamedSet}
            • *
          • *
          • {@link Dimension} (shared)
          • *
        • *
      • *
    • *
    *
*

* * @author Luc Boudreau * @version $Id: Database.java 483 2012-01-05 23:43:18Z jhyde $ * @since Jan 15 2011 */ public interface Database { /** * Retrieves the parent {@link OlapConnection} of this * Database object. * @return The parent conenction object. */ OlapConnection getOlapConnection(); /** * Returns the unique name of this Database. * @return The database name. * @throws OlapException if error occurs. */ String getName() throws OlapException; /** * Returns a human-readable description of this Database. * * @return The database description. Can be null. * @throws OlapException if error occurs. */ String getDescription() throws OlapException; /** * Returns a redirection URL. This value is used only in * distributed architectures. An OLAP server can serve as a * frontal distribution server and redirect clients to delegate * servers. * *

Implementations are free to implement a distributed system. * Most implementations don't make any use of it and * will return the same URL which was used to connect in * the first place. * * @return The database URL. Can be null. * @throws OlapException if error occurs. */ String getURL() throws OlapException; /** * Returns provider-specific information. * * @return A string containing provider-specific information. * @throws OlapException if error cccurs */ String getDataSourceInfo() throws OlapException; /** * Returns the name of the underlying OLAP provider. * *

This usually is the server vendor name, for example "Mondrian" or * "MSOLAP". * * @return The provider name. * @throws OlapException if error occurs. */ String getProviderName() throws OlapException; /** * Returns the types of data that are supported by this provider. * * @return The provider types. * @throws OlapException if error occurs. */ List getProviderTypes() throws OlapException; /** * Returns the authentication modes supported by this * server. * @return The authentication mode supported. * @throws OlapException if error occurs. */ List getAuthenticationModes() throws OlapException; /** * Returns a list of {@link Catalog} objects which belong to * this Database. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapConnection#getOlapCatalogs() * @return List of Catalog in this Database * @throws OlapException if error occurs */ NamedList getCatalogs() throws OlapException; /** * Describes the supported authentication modes. */ public enum AuthenticationMode { /** * Designates providers which don't support * authentication. */ Unauthenticated("No user ID or password needs to be sent."), /** * Designates providers which support authentication * through the JDBC interface. */ Authenticated( "User ID and Password must be included in the information required" + " for the connection."), /** * Designates providers which support authentication through * vendor or implementation specific means. */ Integrated( "The data source uses the underlying security to determine " + "authorization, such as Integrated Security provided by " + "Microsoft Internet Information Services (IIS)."); private final String description; AuthenticationMode(String description) { this.description = description; } /** * Provides a human readable description of the authentication mode. * @return A description string. */ public String getDescription() { return description; } } /** * Describes the possible provider types. */ public static enum ProviderType { /** * Designates providers which provide results in the form of * tabular data sets. */ TDP("Tabular Data Provider."), /** * Designates providers which provide results in the form of * multidimensional data sets. */ MDP("Multidimensional Data Provider."), /** * Designates providers which provide results optimized for * data mining operations. */ DMP( "Data Mining Provider. A DMP provider implements the OLE DB for " + "Data Mining specification."); private final String description; private ProviderType(String description) { this.description = description; } /** * Provides a human readable description of the provider type. * @return A description string. */ public String getDescription() { return description; } } } // End Database.java olap4j-1.0.1.500/src/org/olap4j/metadata/Hierarchy.java0000644000175000017500000000650311707254772022231 0ustar drazzibdrazzib/* // $Id: Hierarchy.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.OlapException; /** * An organization of the set of {@link Member}s in a {@link Dimension} and * their positions relative to one another. * *

A Hierarchy is a collection of {@link Level}s, each of which is a * category of similar {@link Member}s.

* *

A Dimension must have at least one Hierarchy, and may have more than one, * but most have exactly one Hierarchy.

* * @author jhyde * @version $Id: Hierarchy.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 23, 2006 */ public interface Hierarchy extends MetadataElement { /** * Returns the {@link Dimension} this Hierarchy belongs to. * * @return dimension this hierarchy belongs to */ Dimension getDimension(); /** * Returns a list of the {@link Level} objects in this * Hierarchy. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getLevels * * @return list of levels */ NamedList getLevels(); /** * Returns whether this Hierarchy has an 'all' member. * * @return whether this hierarchy has an 'all' member */ boolean hasAll(); /** * Returns the default {@link Member} of this Hierarchy. * *

If the hierarchy has an 'all' member, this member is often the * default. * * @return the default member of this hierarchy */ Member getDefaultMember() throws OlapException; /** * Returns the root member or members of this Dimension. * *

If the dimension has an 'all' member, then this will be the sole * root member. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* *

The result is similar to that returned by * getLevels().get(0).getMembers(); the contents will be the * same, but this method returns a {@link NamedList} rather than a * mere {@link java.util.List} because the members of the root level are * known to have unique names. * * @return root members of this hierarchy * * @throws OlapException on database error */ NamedList getRootMembers() throws OlapException; } // End Hierarchy.java olap4j-1.0.1.500/src/org/olap4j/metadata/XmlaConstants.java0000644000175000017500000006357511707254772023125 0ustar drazzibdrazzib/* // $Id: XmlaConstants.java 485 2012-01-17 06:57:57Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; /** * Collection of various enumerations and constants defined by the XML for * Analysis (XMLA) and OLE DB for OLAP specifications. * * @author jhyde * @version $Id: XmlaConstants.java 485 2012-01-17 06:57:57Z jhyde $ */ public class XmlaConstants { // Suppresses default constructor, ensuring non-instantiability. private XmlaConstants() { } public enum VisualMode implements XmlaConstant { DEFAULT( 0, "Provider-dependent. In Microsoft SQL Server 2000 Analysis " + "Services, this is equivalent to " + "DBPROPVAL_VISUAL_MODE_ORIGINAL."), VISUAL( 1, "Visual totals are enabled."), ORIGINAL( 2, "Visual totals are not enabled."); private final int xmlaOrdinal; private final String description; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(VisualMode.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } VisualMode( int xmlaOrdinal, String description) { this.xmlaOrdinal = xmlaOrdinal; this.description = description; } public String xmlaName() { return "DBPROPVAL_VISUAL_MODE_"; } public String getDescription() { return description; } public int xmlaOrdinal() { return xmlaOrdinal; } } public static enum Method implements XmlaConstant { DISCOVER, EXECUTE, DISCOVER_AND_EXECUTE; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(Method.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } public String xmlaName() { return name(); } public String getDescription() { return null; } public int xmlaOrdinal() { return -1; } } public enum Access implements XmlaConstant { Read(1), Write(2), ReadWrite(3); private final int xmlaOrdinal; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(Access.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } Access(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return name(); } public String getDescription() { return null; } public int xmlaOrdinal() { return xmlaOrdinal; } } public static enum AuthenticationMode implements XmlaConstant { Unauthenticated("no user ID or password needs to be sent."), Authenticated( "User ID and Password must be included in the information required " + "for the connection."), Integrated( "the data source uses the underlying security to determine " + "authorization, such as Integrated Security provided by " + "Microsoft Internet Information Services (IIS)."); private final String description; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(AuthenticationMode.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } AuthenticationMode(String description) { this.description = description; } public String xmlaName() { return name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return -1; } } public static enum ProviderType implements XmlaConstant { TDP("tabular data provider."), MDP("multidimensional data provider."), DMP( "data mining provider. A DMP provider implements the OLE DB for " + "Data Mining specification."); private final String description; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(ProviderType.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } private ProviderType(String description) { this.description = description; } public String xmlaName() { return name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return -1; } } public static enum Updateable implements XmlaConstant { MD_MASK_ENABLED( 0x00000000, "The cell can be updated."), MD_MASK_NOT_ENABLED( 0x10000000, "The cell cannot be updated."), CELL_UPDATE_ENABLED( 0x00000001, "Cell can be updated in the cellset."), CELL_UPDATE_ENABLED_WITH_UPDATE( 0x00000002, "The cell can be updated with an update statement. The update may " + "fail if a leaf cell is updated that is not write-enabled."), CELL_UPDATE_NOT_ENABLED_FORMULA( 0x10000001, "The cell cannot be updated because the cell has a calculated " + "member among its coordinates; the cell was retrieved with a set " + "in the where clause. A cell can be updated even though a " + "formula affects, or a calculated cell is on, the value of a " + "cell (is somewhere along the aggregation path). In this " + "scenario, the final value of the cell may not be the updated " + "value, because the calculation will affect the result."), CELL_UPDATE_NOT_ENABLED_NONSUM_MEASURE( 0x10000002, "The cell cannot be updated because non-sum measures (count, min, " + "max, distinct count, semi-additive) can not be updated."), CELL_UPDATE_NOT_ENABLED_NACELL_VIRTUALCUBE( 0x10000003, "The cell cannot be updated because the cell does not exist as it " + "is at the intersection of a measure and a dimension member " + "unrelated to the measure’s measure group."), CELL_UPDATE_NOT_ENABLED_SECURE( 0x10000005, "The cell cannot be updated because the cell is secured."), CELL_UPDATE_NOT_ENABLED_CALCLEVEL( 0x10000006, "Reserved for future use."), CELL_UPDATE_NOT_ENABLED_CANNOTUPDATE( 0x10000007, "The cell cannot be updated because of internal reasons."), CELL_UPDATE_NOT_ENABLED_INVALIDDIMENSIONTYPE( 0x10000009, "The cell cannot be updated because update is not supported in " + "mining model, indirect, or data mining dimensions."); private final int xmlaOrdinal; private final String description; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(Updateable.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } Updateable(int xmlaOrdinal, String description) { this.xmlaOrdinal = xmlaOrdinal; this.description = description; } public String xmlaName() { return name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return xmlaOrdinal; } } public static enum FontFlag implements XmlaConstant { BOLD(1), ITALIC(2), UNDERLINE(4), STRIKEOUT(8); private final int xmlaOrdinal; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(FontFlag.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } FontFlag(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MDFF_" + name(); } public String getDescription() { return name(); } public int xmlaOrdinal() { return xmlaOrdinal; } } /** * Action type. * *

Fields correspond to XMLA constants MDACTION_TYPE_URL (0x01), * MDACTION_TYPE_HTML (0x02), * MDACTION_TYPE_STATEMENT (0x04), * MDACTION_TYPE_DATASET (0x08), * MDACTION_TYPE_ROWSET (0x10), * MDACTION_TYPE_COMMANDLINE (0x20), * MDACTION_TYPE_PROPRIETARY (0x40), * MDACTION_TYPE_REPORT (0x80), * MDACTION_TYPE_DRILLTHROUGH (0x100)

*/ public static enum ActionType implements XmlaConstant { URL(0x01), HTML(0x02), STATEMENT(0x04), DATASET(0x08), ROWSET(0x10), COMMANDLINE(0x20), PROPRIETARY(0x40), REPORT(0x80), DRILLTHROUGH(0x100); private final int xmlaOrdinal; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(ActionType.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } ActionType(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MDACTION_TYPE_" + name(); } public String getDescription() { return name(); } public int xmlaOrdinal() { return xmlaOrdinal; } } /** * How the COORDINATE restriction column is interpreted. * *

Fields correspond to the XMLA values * MDACTION_COORDINATE_CUBE (1), * MDACTION_COORDINATE_DIMENSION (2) * MDACTION_COORDINATE_LEVEL (3), * MDACTION_COORDINATE_MEMBER (4), * MDACTION_COORDINATE_SET (5), * MDACTION_COORDINATE_CELL (6)

*/ public static enum CoordinateType implements XmlaConstant { CUBE(1), DIMENSION(2), LEVEL(3), MEMBER(4), SET(5), CELL(6); private final int xmlaOrdinal; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(ActionType.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } CoordinateType(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MDACTION_COORDINATE_" + name(); } public String getDescription() { return name(); } public int xmlaOrdinal() { return xmlaOrdinal; } } /** * The only OLE DB Types Indicators returned by SQL Server are thoses coded * below. */ public enum DBType implements XmlaConstant { /* * The following values exactly match VARENUM * in Automation and may be used in VARIANT. */ I4( "INTEGER", 3, "DBTYPE_I4", "A four-byte, signed integer: INTEGER"), R8( "DOUBLE", 5, "DBTYPE_R8", "A double-precision floating-point value: Double"), CY( "CURRENCY", 6, "DBTYPE_CY", "A currency value: LARGE_INTEGER, Currency is a fixed-point number " + "with four digits to the right of the decimal point. It is " + "stored in an eight-byte signed integer, scaled by 10,000."), BOOL( "BOOLEAN", 11, "DBTYPE_BOOL", "A Boolean value stored in the same way as in Automation: " + "VARIANT_BOOL; 0 means false and ~0 (bitwise, the value is not " + "0; that is, all bits are set to 1) means true."), /** * Used by SQL Server for value. */ VARIANT( "VARIANT", 12, "DBTYPE_VARIANT", "An Automation VARIANT"), /** * Used by SQL Server for font size. */ UI2("UNSIGNED_SHORT", 18, "DBTYPE_UI2", "A two-byte, unsigned integer"), /** * Used by SQL Server for colors, font flags and cell ordinal. */ UI4( "UNSIGNED_INTEGER", 19, "DBTYPE_UI4", "A four-byte, unsigned integer"), /* * The following values exactly match VARENUM * in Automation but cannot be used in VARIANT. */ I8( "LARGE_INTEGER", 20, "DBTYPE_I8", "An eight-byte, signed integer: LARGE_INTEGER"), /* * The following values are not in VARENUM in OLE. */ WSTR( "STRING", 130, "DBTYPE_WSTR", "A null-terminated Unicode character string: wchar_t[length]; If " + "DBTYPE_WSTR is used by itself, the number of bytes allocated " + "for the string, including the null-termination character, is " + "specified by cbMaxLen in the DBBINDING structure. If " + "DBTYPE_WSTR is combined with DBTYPE_BYREF, the number of bytes " + "allocated for the string, including the null-termination " + "character, is at least the length of the string plus two. In " + "either case, the 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."); public final String userName; /** * The length of a non-numeric column or parameter that refers to either * the maximum or the length defined for this type by the provider. For * character data, this is the maximum or defined length in characters. * For DateTime data types, this is the length of the string * representation (assuming the maximum allowed precision of the * fractional seconds component). * * If the data type is numeric, this is the upper bound on the maximum * precision of the data type. int columnSize; */ private final int xmlaOrdinal; /* * A Boolean that indicates whether the data type is nullable. * VARIANT_TRUE indicates that the data type is nullable. * VARIANT_FALSE indicates that the data type is not nullable. * NULL-- indicates that it is not known whether the data type is * nullable. boolean isNullable; */ private String description; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(DBType.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } DBType( String userName, int xmlaOrdinal, String dbTypeIndicator, String description) { this.userName = userName; this.xmlaOrdinal = xmlaOrdinal; this.description = description; assert xmlaName().equals(dbTypeIndicator); } public String xmlaName() { return "DBTYPE_" + name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return xmlaOrdinal; } } public enum Format implements XmlaConstant { Tabular( "a flat or hierarchical rowset. Similar to the XML RAW format in " + "SQL. The Format property should be set to Tabular for OLE DB " + "for Data Mining commands."), Multidimensional( "Indicates that the result set will use the MDDataSet format " + "(Execute method only)."), Native( "The client does not request a specific format, so the provider " + "may return the format appropriate to the query. (The actual " + "result type is identified by namespace of the result.)"); private final String description; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(Format.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } Format(String description) { this.description = description; } public String xmlaName() { return name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return -1; } } public enum AxisFormat implements XmlaConstant { TupleFormat( "The MDDataSet axis is made up of one or more CrossProduct " + "elements."), ClusterFormat( "Analysis Services uses the TupleFormat format for this setting."), CustomFormat( "The MDDataSet axis contains one or more Tuple elements."); private final String description; private static final XmlaConstant.Dictionary DICTIONARY = DictionaryImpl.forClass(AxisFormat.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static XmlaConstant.Dictionary getDictionary() { return DICTIONARY; } AxisFormat(String description) { this.description = description; } public String xmlaName() { return name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return -1; } } public enum Content { None, Schema, Data, SchemaData, DataOmitDefaultSlicer, DataIncludeDefaultSlicer; /** The content type default value - shared across more than one file */ public static final Content DEFAULT = SchemaData; } public enum MdxSupport { Core } public enum StateSupport { None, Sessions } public enum Literal implements XmlaConstant { CATALOG_NAME( 2, null, 24, ".", "0123456789", "A catalog name in a text command."), CATALOG_SEPARATOR(3, ".", 0, null, null, null), COLUMN_ALIAS(5, null, -1, "'\"[]", "0123456789", null), COLUMN_NAME(6, null, -1, ".", "0123456789", null), CORRELATION_NAME(7, null, -1, "'\"[]", "0123456789", null), CUBE_NAME(21, null, -1, ".", "0123456789", null), DIMENSION_NAME(22, null, -1, ".", "0123456789", null), HIERARCHY_NAME(23, null, -1, ".", "0123456789", null), LEVEL_NAME(24, null, -1, ".", "0123456789", null), MEMBER_NAME(25, null, -1, ".", "0123456789", null), PROCEDURE_NAME(14, null, -1, ".", "0123456789", null), PROPERTY_NAME(26, null, -1, ".", "0123456789", null), QUOTE( 15, "[", -1, null, null, "The character used in a text command as the opening quote for " + "quoting identifiers that contain special characters."), QUOTE_SUFFIX( 28, "]", -1, null, null, "The character used in a text command as the closing quote for " + "quoting identifiers that contain special characters. 1.x " + "providers that use the same character as the prefix and suffix " + "may not return this literal value and can set the lt member of " + "the DBLITERAL structure to DBLITERAL_INVALID if requested."), TABLE_NAME(17, null, -1, ".", "0123456789", null), TEXT_COMMAND( 18, null, -1, null, null, "A text command, such as an SQL statement."), USER_NAME(19, null, 0, null, null, null); /* // Enum DBLITERALENUM and DBLITERALENUM20, OLEDB.H. public static final int DBLITERAL_INVALID = 0, DBLITERAL_BINARY_LITERAL = 1, DBLITERAL_CATALOG_NAME = 2, DBLITERAL_CATALOG_SEPARATOR = 3, DBLITERAL_CHAR_LITERAL = 4, DBLITERAL_COLUMN_ALIAS = 5, DBLITERAL_COLUMN_NAME = 6, DBLITERAL_CORRELATION_NAME = 7, DBLITERAL_CURSOR_NAME = 8, DBLITERAL_ESCAPE_PERCENT = 9, DBLITERAL_ESCAPE_UNDERSCORE = 10, DBLITERAL_INDEX_NAME = 11, DBLITERAL_LIKE_PERCENT = 12, DBLITERAL_LIKE_UNDERSCORE = 13, DBLITERAL_PROCEDURE_NAME = 14, DBLITERAL_QUOTE = 15, DBLITERAL_QUOTE_PREFIX = DBLITERAL_QUOTE, DBLITERAL_SCHEMA_NAME = 16, DBLITERAL_TABLE_NAME = 17, DBLITERAL_TEXT_COMMAND = 18, DBLITERAL_USER_NAME = 19, DBLITERAL_VIEW_NAME = 20, DBLITERAL_CUBE_NAME = 21, DBLITERAL_DIMENSION_NAME = 22, DBLITERAL_HIERARCHY_NAME = 23, DBLITERAL_LEVEL_NAME = 24, DBLITERAL_MEMBER_NAME = 25, DBLITERAL_PROPERTY_NAME = 26, DBLITERAL_SCHEMA_SEPARATOR = 27, DBLITERAL_QUOTE_SUFFIX = 28; */ private int xmlaOrdinal; private final String literalValue; private final int literalMaxLength; private final String literalInvalidChars; private final String literalInvalidStartingChars; private final String description; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(Literal.class); /** * Per {@link XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } Literal( int xmlaOrdinal, String literalValue, int literalMaxLength, String literalInvalidChars, String literalInvalidStartingChars, String description) { this.xmlaOrdinal = xmlaOrdinal; this.literalValue = literalValue; this.literalMaxLength = literalMaxLength; this.literalInvalidChars = literalInvalidChars; this.literalInvalidStartingChars = literalInvalidStartingChars; this.description = description; } public String getLiteralName() { return xmlaName(); } public String getLiteralValue() { return literalValue; } public String getLiteralInvalidChars() { return literalInvalidChars; } public String getLiteralInvalidStartingChars() { return literalInvalidStartingChars; } public int getLiteralMaxLength() { return literalMaxLength; } public String xmlaName() { return "DBLITERAL_" + name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return xmlaOrdinal; } } public interface EnumWithDesc { String getDescription(); } } // End XmlaConstants.java olap4j-1.0.1.500/src/org/olap4j/metadata/Schema.java0000644000175000017500000000710111707254772021506 0ustar drazzibdrazzib/* // $Id: Schema.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.OlapException; import java.util.Collection; import java.util.Locale; /** * A collection of database objects that contain structural information, or * metadata, about a database. * *

A Schema belongs to a {@link Catalog} and contains a number of * {@link Cube}s and shared {@link Dimension}s. * * @author jhyde * @version $Id: Schema.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 13, 2006 */ public interface Schema { /** * Returns the {@link Catalog} this Schema belongs to. * * @return catalog this schema belongs to */ Catalog getCatalog(); /** * Returns the name of this Schema. * * @return name of this Schema */ String getName(); /** * Returns a list of cubes in this Schema. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getCubes * @return List of cubes in this Schema * * @throws OlapException if database error occurs */ NamedList getCubes() throws OlapException; /** * Returns a list of shared {@link Dimension} objects in this * Schema. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getDimensions(String,String,String,String) * * @return list of shared dimensions * * @throws OlapException if database error occurs */ 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 * * @throws OlapException if database error occurs */ Collection getSupportedLocales() throws OlapException; } // End Schema.java olap4j-1.0.1.500/src/org/olap4j/metadata/Level.java0000644000175000017500000003144111707254772021361 0ustar drazzibdrazzib/* // $Id: Level.java 485 2012-01-17 06:57:57Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.OlapException; import java.util.List; /** * Group of {@link Member} objects in a {@link Hierarchy}, * all with the same attributes and at the same depth in the hierarchy. * * @author jhyde * @version $Id: Level.java 485 2012-01-17 06:57:57Z jhyde $ * @since Aug 23, 2006 */ public interface Level extends MetadataElement { /** * Returns the depth of this Level. * *

Note #1: In an access-controlled context, the first visible level of * a hierarchy may not have a depth of 0.

* *

Note #2: In a parent-child hierarchy, the depth of a member (as * returned by may not be the same as the depth of its level. * * @return depth of this level */ int getDepth(); /** * Returns the {@link Hierarchy} this Level belongs to. * * @return hierarchy this level belongs to */ Hierarchy getHierarchy(); /** * Returns the Dimension this Level belongs to. * (Always equivalent to getHierarchy().getDimension().) * * @return dimension this level belongs to */ Dimension getDimension(); /** * Returns the type of this Level. * * @return level type */ Level.Type getLevelType(); /** * Returns whether the level is calculated. * * @return Whether this level is calculated */ boolean isCalculated(); /** * Returns a list of definitions for the properties available to members * of this Level. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getProperties * * @return properties of this Level */ NamedList getProperties(); /** * Returns a list of {@link Member} objects that belong to this Level. * *

The list does not include calculated members.

* *

Some levels have a very many members. In this case, calling this * method may be expensive in space and/or time and is not recommended.

* *

If you need to include calculated members, or if you need to query * specific members or subsets of members in a level, consider instead * generating and executing an MDX query with a single axis. MDX functions * {@code AddCalculatedMembers}, {@code Filter} and {@code Order} are * especially useful. For example, * *

with member [Measures].[Zero] as 0
     * select AddCalculatedMembers([Time].[Month].Members) on 0
     * from [Sales]
     * where [Measures].[Zero]
* * returns the {@code [Month]} level including calculated members. The * {@code [Measures].[Zero]} calculated member saves the OLAP server the * effort of retrieving cell values.

* *

The members of a level do not have unique names, so unlike * {@link Hierarchy#getRootMembers()} and * {@link Member#getChildMembers()} the result type * is a {@link List} not a {@link NamedList}. * * @return List of members in this Level * * @throws OlapException if database error occurs */ List getMembers() throws OlapException; /** * Returns the number of members in this Level. * * @return number of members */ int getCardinality(); /** * Enumeration of the types of a {@link Level}. * *

Several of the values are defined by OLE DB for OLAP and/or XML/A, * sans the "MDLEVEL_TYPE_" prefix to their name. For example, * {@link #GEO_CONTINENT} corresponds to * the value MDLEVEL_TYPE_GEO_CONTINENT for the * LEVEL_TYPE property in the MDSCHEMA_LEVELS * schema rowset. * *

Some of the values are specified by OLE DB for OLAP: *

    *
  • MDLEVEL_TYPE_REGULAR (0x0000) *
  • MDLEVEL_TYPE_ALL (0x0001) *
  • MDLEVEL_TYPE_TIME_YEARS (0x0014) *
  • MDLEVEL_TYPE_TIME_HALF_YEAR (0x0024) *
  • MDLEVEL_TYPE_TIME_QUARTERS (0x0044) *
  • MDLEVEL_TYPE_TIME_MONTHS (0x0084) *
  • MDLEVEL_TYPE_TIME_WEEKS (0x0104) *
  • MDLEVEL_TYPE_TIME_DAYS (0x0204) *
  • MDLEVEL_TYPE_TIME_HOURS (0x0304) *
  • MDLEVEL_TYPE_TIME_MINUTES (0x0404) *
  • MDLEVEL_TYPE_TIME_SECONDS (0x0804) *
  • MDLEVEL_TYPE_TIME_UNDEFINED (0x1004) *
* * Some of the OLE DB for OLAP values are as flags, and do not become * values of the enumeration: *
    *
  • MDLEVEL_TYPE_UNKNOWN (0x0000) signals that no other flags are set. * Use {@link #REGULAR} *
  • MDLEVEL_TYPE_CALCULATED (0x0002) indicates that the level is * calculated. Use {@link Level#isCalculated}. *
  • MDLEVEL_TYPE_TIME (0x0004) indicates that the level is time-related. * Use {@link #isTime}. *
  • MDLEVEL_TYPE_RESERVED1 (0x0008) is reserved for future use. *
* *

Some of the values are specified by XMLA: *

    *
  • MDLEVEL_TYPE_GEO_CONTINENT (0x2001) *
  • MDLEVEL_TYPE_GEO_REGION (0x2002) *
  • MDLEVEL_TYPE_GEO_COUNTRY (0x2003) *
  • MDLEVEL_TYPE_GEO_STATE_OR_PROVINCE (0x2004) *
  • MDLEVEL_TYPE_GEO_COUNTY (0x2005) *
  • MDLEVEL_TYPE_GEO_CITY (0x2006) *
  • MDLEVEL_TYPE_GEO_POSTALCODE (0x2007) *
  • MDLEVEL_TYPE_GEO_POINT (0x2008) *
  • MDLEVEL_TYPE_ORG_UNIT (0x1011) *
  • MDLEVEL_TYPE_BOM_RESOURCE (0x1012) *
  • MDLEVEL_TYPE_QUANTITATIVE (0x1013) *
  • MDLEVEL_TYPE_ACCOUNT (0x1014) *
  • MDLEVEL_TYPE_CUSTOMER (0x1021) *
  • MDLEVEL_TYPE_CUSTOMER_GROUP (0x1022) *
  • MDLEVEL_TYPE_CUSTOMER_HOUSEHOLD (0x1023) *
  • MDLEVEL_TYPE_PRODUCT (0x1031) *
  • MDLEVEL_TYPE_PRODUCT_GROUP (0x1032) *
  • MDLEVEL_TYPE_SCENARIO (0x1015) *
  • MDLEVEL_TYPE_UTILITY (0x1016) *
  • MDLEVEL_TYPE_PERSON (0x1041) *
  • MDLEVEL_TYPE_COMPANY (0x1042) *
  • MDLEVEL_TYPE_CURRENCY_SOURCE (0x1051) *
  • MDLEVEL_TYPE_CURRENCY_DESTINATION (0x1052) *
  • MDLEVEL_TYPE_CHANNEL (0x1061) *
  • MDLEVEL_TYPE_REPRESENTATIVE (0x1062) *
  • MDLEVEL_TYPE_PROMOTION (0x1071) *
* * @see Level#getLevelType * @see org.olap4j.OlapDatabaseMetaData#getLevels */ public enum Type implements XmlaConstant { /** * Indicates that the level is not related to time. */ REGULAR(0x0000), /** * Indicates that the level contains the 'all' member of its hierarchy. */ ALL(0x0001), /** * Indicates that a level holds the null member. Does not correspond to * an XMLA or OLE DB value. */ NULL(-1), /** * Indicates that a level refers to years. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_YEARS(0x0014), /** * Indicates that a level refers to half years. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_HALF_YEAR(0x0024), /** * Indicates that a level refers to quarters. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_QUARTERS(0x0044), /** * Indicates that a level refers to months. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_MONTHS(0x0084), /** * Indicates that a level refers to weeks. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_WEEKS(0x0104), /** * Indicates that a level refers to days. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_DAYS(0x0204), /** * Indicates that a level refers to hours. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_HOURS(0x0304), /** * Indicates that a level refers to minutes. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_MINUTES(0x0404), /** * Indicates that a level refers to seconds. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_SECONDS(0x0804), /** * Indicates that a level refers to days. * It must be used in a dimension whose type is * {@link org.olap4j.metadata.Dimension.Type#TIME}. */ TIME_UNDEFINED(0x1004), GEO_CONTINENT(0x2001), GEO_REGION(0x2002), GEO_COUNTRY(0x2003), GEO_STATE_OR_PROVINCE(0x2004), GEO_COUNTY(0x2005), GEO_CITY(0x2006), GEO_POSTALCODE(0x2007), GEO_POINT(0x2008), ORG_UNIT(0x1011), BOM_RESOURCE(0x1012), QUANTITATIVE(0x1013), ACCOUNT(0x1014), CUSTOMER(0x1021), CUSTOMER_GROUP(0x1022), CUSTOMER_HOUSEHOLD(0x1023), PRODUCT(0x1031), PRODUCT_GROUP(0x1032), SCENARIO(0x1015), UTILITY(0x1016), PERSON(0x1041), COMPANY(0x1042), CURRENCY_SOURCE(0x1051), CURRENCY_DESTINATION(0x1052), CHANNEL(0x1061), REPRESENTATIVE(0x1062), PROMOTION(0x1071); private final int xmlaOrdinal; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(Type.class); /** * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } /** * Creates a level type. * * @param xmlaOrdinal Ordinal code in XMLA or OLE DB for OLAP * specification */ private Type(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MDLEVEL_TYPE_" + name(); } public String getDescription() { return ""; } public int xmlaOrdinal() { return xmlaOrdinal; } /** * Returns whether this is a time-related level * ({@link #TIME_YEARS}, * {@link #TIME_HALF_YEAR}, * {@link #TIME_QUARTERS}, * {@link #TIME_MONTHS}, * {@link #TIME_WEEKS}, * {@link #TIME_DAYS}, * {@link #TIME_HOURS}, * {@link #TIME_MINUTES}, * {@link #TIME_SECONDS}, * {@link #TIME_UNDEFINED}). * * @return whether this is a time-related level */ public boolean isTime() { switch (this) { case TIME_YEARS: case TIME_HALF_YEAR: case TIME_QUARTERS: case TIME_MONTHS: case TIME_WEEKS: case TIME_DAYS: case TIME_HOURS: case TIME_MINUTES: case TIME_SECONDS: case TIME_UNDEFINED: return true; default: return false; } } } } // End Level.java olap4j-1.0.1.500/src/org/olap4j/metadata/Member.java0000644000175000017500000003117011707254772021520 0ustar drazzibdrazzib/* // $Id: Member.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.OlapException; import org.olap4j.mdx.ParseTreeNode; import java.util.List; /** * Member is a data value in an OLAP Dimension. * * @author jhyde * @version $Id: Member.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface Member extends MetadataElement { /** * Returns the children of this Member, indexed by name. * *

If access-control is in place, the list does not contain inaccessible * children. * *

If the member has no children, returns an empty list: the result is * never null. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getMembers * * @return children of this member * * @throws OlapException if database error occurs */ NamedList getChildMembers() throws OlapException; /** * Returns the number of children this Member has. * *

This method has the same effect as * getChildMembers().size(), but is typically less expensive. * * @return number of children * * @throws OlapException if database error occurs */ int getChildMemberCount() throws OlapException; /** * Returns the parent of this Member, or null if it has no parent. * * @return Parent member, or null if member has no parent */ Member getParentMember(); /** * Returns the Level of this Member. * *

Never returns null.

* * @return Level which this Member belongs to */ Level getLevel(); /** * Returns the Hierarchy of this Member. * *

Never returns null. * Result is always the same as getLevel().getHierarchy(). * * @return Hierarchy which this Member belongs to */ Hierarchy getHierarchy(); /** * Returns the Dimension of this Member. * *

Never returns null. Result is always the same as * getLevel().getHierarchy().getDimension(). * * @return Dimension which this Member belongs to */ Dimension getDimension(); /** * Returns the type of this Member. * *

Never returns null.

* * @return What kind of member this is */ Type getMemberType(); /** * Returns whether this Member represents the aggregation of all members * in its Dimension. * *

An 'all' member is always the root of its Hierarchy; that is, * its parent member is the null member, and * {@link Hierarchy#getRootMembers()} returns the 'all' * member and no others. Some hierarchies do not have an 'all' member. * * @see Hierarchy#hasAll() * * @return whether this Member is the 'all' member of its Dimension */ boolean isAll(); /** * Enumeration of types of members. * *

The values are as specified by XMLA, * plus the additional {@link #NULL} value not used by XMLA. * For example, XMLA specifies MDMEMBER_TYPE_REGULAR with * ordinal 1, which corresponds to value {@link #REGULAR}. * *

The {@link #FORMULA} value takes precedence over {@link #MEASURE}. * For example, if there is a formula (calculated) member on the Measures * dimension, it is listed as FORMULA. */ enum Type { UNKNOWN(0), REGULAR(1), ALL(2), MEASURE(3), FORMULA(4), /** * Indicates that this member is its hierarchy's NULL member (such as is * returned by the expression * [Gender].[All Gender].PrevMember, for example). */ NULL(5); private Type(int ordinal) { assert ordinal == ordinal(); } } /** * Returns whether member is equal to, a child of, or a * descendent of this Member. * * @param member Member * @return Whether the given Member is a descendent of this Member */ boolean isChildOrEqualTo(Member member); /** * Returns whether this member is calculated using a formula. * *

Examples of calculated members include * those defined using a WITH MEMBER clause in an MDX query * ({@link #getMemberType()} will return {@link Type#FORMULA} for these), * or a calculated member defined in a cube. * * @return Whether this Member is calculated * * @see #isCalculatedInQuery() */ boolean isCalculated(); /** * Returns the solve order of this member in a formula. * * @return solve order of this Member */ int getSolveOrder(); /** * Expression by which this member is derived, if it is a calculated * member. If the member is not calulated, returns null. * * @return expression for this member */ ParseTreeNode getExpression(); /** * Returns array of all members which are ancestor to this. * * @return ancestor Members */ List getAncestorMembers(); /** * Returns whether this member is computed from a WITH MEMBER * clause in an MDX query. (Calculated members can also be calculated in a * cube.) * * @return Whether this member is calculated in a query * * @see #isCalculated() */ boolean isCalculatedInQuery(); /** * Returns the value of a given property. * *

Returns null if the property is not set.

* *

Every member has certain system properties such as "name" and * "caption" (the full list is described in the * {@link org.olap4j.metadata.Property.StandardMemberProperty} * enumeration), as well as extra properties defined for its Level * (see {@link Level#getProperties()}).

* * @param property Property * * @return formatted value of the given property * * @see #getPropertyFormattedValue(Property) * * @throws OlapException if database error occurs */ Object getPropertyValue(Property property) throws OlapException; /** * Returns the formatted value of a given property. * *

Returns null if the property is not set.

* *

Every member has certain system properties such as "name" and * "caption" (the full list is described in the * {@link org.olap4j.metadata.Property.StandardMemberProperty} * enumeration), as well as extra properties defined for its Level * (see {@link Level#getProperties()}).

* * @param property Property * * @return formatted value of the given property * * @see #getPropertyValue(Property) * * @throws OlapException if database error occurs */ String getPropertyFormattedValue(Property property) throws OlapException; /** * Sets a property of this member to a given value. * *

Every member has certain system properties such as "name" and * "caption" (the full list is described in the * {@link org.olap4j.metadata.Property.StandardMemberProperty} * enumeration), as well as extra properties defined for its Level * (see {@link Level#getProperties()}).

* * @param property property * * @param value Property value * * @throws OlapException if the value not valid for this property * (for example, a String value assigned to a Boolean property) */ void setProperty(Property property, Object value) throws OlapException; /** * Returns the definitions of the properties this member may have. * *

For many providers, properties are defined against a Level, so result * of this method will be identical to * member.getLevel().{@link Level#getProperties() getProperties}(). * * @return properties of this Member */ NamedList getProperties(); /** * Returns the ordinal of the member. * * @return ordinal of this Member */ int getOrdinal(); /** * Returns whether this member is 'hidden', as per the rules which define * a ragged hierarchy. * * @return whether this member is a hidden member of a ragged hierarchy */ boolean isHidden(); /** * Returns the depth of this member. * *

In regular hierarchies, this is as the same as the level's depth, * but in parent-child and ragged hierarchies the value may be * different.

* * @return depth of this Member */ int getDepth(); /** * Returns the system-generated data member that is associated with a * non-leaf member of a dimension. * *

Returns this member if this member is a leaf member, or if the * non-leaf member does not have an associated data member.

* * @return system-generated data member */ Member getDataMember(); /** * Enumeration of tree operations which can be used when querying * members. * *

Some of the values are as specified by XMLA. * For example, XMLA specifies MDTREEOP_CHILDREN with ordinal 1, * which corresponds to the value {@link #CHILDREN}. * * @see org.olap4j.OlapDatabaseMetaData#getMembers */ public enum TreeOp implements XmlaConstant { /** * Tree operation which returns only the immediate children. */ CHILDREN( 1, "Tree operation which returns only the immediate children."), /** * Tree operation which returns members on the same level. */ SIBLINGS( 2, "Tree operation which returns members on the same level."), /** * Tree operation which returns only the immediate parent. */ PARENT( 4, "Tree operation which returns only the immediate parent."), /** * Tree operation which returns itself in the list of returned rows. */ SELF( 8, "Tree operation which returns itself in the list of returned " + "rows."), /** * Tree operation which returns all of the descendants. */ DESCENDANTS( 16, "Tree operation which returns all of the descendants."), /** * Tree operation which returns all of the ancestors. */ ANCESTORS( 32, "Tree operation which returns all of the ancestors."); private final int xmlaOrdinal; private String description; private static final Dictionary DICTIONARY = DictionaryImpl.forClass(TreeOp.class); /** * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } private TreeOp(int xmlaOrdinal, String description) { this.xmlaOrdinal = xmlaOrdinal; this.description = description; } public String xmlaName() { return "MDTREEOP_" + name(); } public String getDescription() { return description; } public int xmlaOrdinal() { return xmlaOrdinal; } } } // End Member.java olap4j-1.0.1.500/src/org/olap4j/metadata/Datatype.java0000644000175000017500000001520411707254772022064 0ustar drazzibdrazzib/* // $Id: Datatype.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; /** * Enumeration of the allowable data types of a Property or Measure. * *

The values derive from the OLE DB specification, specifically a * subset of the OLE DB Types Indicators returned by SQL Server. * * @author jhyde * @version $Id: Datatype.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 23, 2006 */ public enum Datatype implements XmlaConstant { /* * The following values exactly match VARENUM * in Automation and may be used in VARIANT. */ INTEGER(3, "DBTYPE_I4", "A four-byte, signed integer: INTEGER"), DOUBLE(5, "DBTYPE_R8", "A double-precision floating-point value: Double"), CURRENCY( 6, "DBTYPE_CY", "A currency value: LARGE_INTEGER, Currency is a fixed-point number with " + "four digits to the right of the decimal point. It is stored in an " + "eight-byte signed integer, scaled by 10,000."), BOOLEAN( 11, "DBTYPE_BOOL", "A Boolean value stored in the same way as in Automation: VARIANT_BOOL; " + "0 means false and ~0 (bitwise, the value is not 0; that is, all bits " + "are set to 1) means true."), /** * Used by SQL Server for value. */ VARIANT(12, "DBTYPE_VARIANT", "An Automation VARIANT"), /** * Used by SQL Server for font size. */ UNSIGNED_SHORT(18, "DBTYPE_UI2", "A two-byte, unsigned integer"), /** * Used by SQL Server for colors, font flags and cell ordinal. */ UNSIGNED_INTEGER(19, "DBTYPE_UI4", "A four-byte, unsigned integer"), /* * The following values exactly match VARENUM * in Automation but cannot be used in VARIANT. */ LARGE_INTEGER( 20, "DBTYPE_I8", "An eight-byte, signed integer: LARGE_INTEGER"), /* * The following values are not in VARENUM in OLE. */ STRING( 130, "DBTYPE_WSTR", "A null-terminated Unicode character string: wchar_t[length]; If " + "DBTYPE_WSTR is used by itself, the number of bytes allocated " + "for the string, including the null-termination character, is " + "specified by cbMaxLen in the DBBINDING structure. If " + "DBTYPE_WSTR is combined with DBTYPE_BYREF, the number of bytes " + "allocated for the string, including the null-termination character, " + "is at least the length of the string plus two. In either case, the " + "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."), /** * 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; private String description; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(Datatype.class); Datatype( int xmlaOrdinal, String dbTypeIndicator, String description) { this.xmlaOrdinal = xmlaOrdinal; this.dbTypeIndicator = dbTypeIndicator; 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; } /** * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } } // End Datatype.java olap4j-1.0.1.500/src/org/olap4j/metadata/NamedList.java0000644000175000017500000000356111707254772022174 0ustar drazzibdrazzib/* // $Id: NamedList.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import java.util.List; /** * Extension to {@link java.util.List} which allows access to members of the * list by name as well as by ordinal. * * @author jhyde * @version $Id: NamedList.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface NamedList extends List { /** * Retrieves a member by name. * * @param name name of the element to return * * @see #get(int) * * @return the element of the list with the specified name, or null if * there is no such element */ E get(String name); /** * Returns the position where a member of a given name is found, or -1 * if the member is not present. * * @param name name of the element to return * * @return the index of element of the list with the specified name, or -1 * if there is no such element * * @see #indexOf(Object) */ int indexOfName(String name); } // End NamedList.java olap4j-1.0.1.500/src/org/olap4j/metadata/Catalog.java0000644000175000017500000000675011707254772021671 0ustar drazzibdrazzib/* // $Id: Catalog.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.*; /** *

Catalogs are the second element of the hierarchy of metadata objects. * A Catalog contains one or more {@link Schema}s and has a parent * {@link Database}.

* *

Some OLAP servers may only have one Catalog. Mondrian is one such * OLAP server; its sole catalog is called "LOCALDB". * *

To obtain the collection of catalogs in the current server, call the * {@link OlapConnection#getOlapCatalogs()} method. * *

The hierarchy of metadata objects, rooted at the connection from which * they are accessed, is as follows: *

*
    *
  • {@link org.olap4j.OlapConnection}
      *
    • {@link Database}
        *
      • {@link Catalog}
          *
        • {@link Schema}
            *
          • {@link Cube}
              *
            • {@link Dimension}
                *
              • {@link Hierarchy}
                  *
                • {@link Level}
                    *
                  • {@link Member}
                  • *
                  • {@link Property}
                  • *
                • *
              • *
            • *
            • {@link NamedSet}
            • *
          • *
          • {@link Dimension} (shared)
          • *
        • *
      • *
    • *
    *
*

* * @author jhyde * @version $Id: Catalog.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 24, 2006 */ public interface Catalog { /** * Returns a list of {@link Schema} objects which belong to * this Catalog. * *

The caller should assume that the list is immutable; * if the caller modifies the list, behavior is undefined.

* * @see org.olap4j.OlapDatabaseMetaData#getSchemas * @return List of Schema in this Catalog * @throws OlapException if error occurs */ NamedList getSchemas() throws OlapException; /** * Returns the name of this Catalog. * * @return name of this Catalog */ String getName(); /** * Retrieves the metadata describing the OLAP server that this Catalog * belongs to. * * @return metadata describing the OLAP server */ OlapDatabaseMetaData getMetaData(); /** * Returns the parent database of this catalog. * @return A Database object to which this catalog belongs. */ Database getDatabase(); } // End Catalog.java olap4j-1.0.1.500/src/org/olap4j/metadata/DictionaryImpl.java0000644000175000017500000000732311707254772023243 0ustar drazzibdrazzib/* // $Id: DictionaryImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; import org.olap4j.impl.Olap4jUtil; import java.util.*; /** * Implementation of {@link org.olap4j.metadata.XmlaConstant.Dictionary}. * * @author jhyde * @version $Id: DictionaryImpl.java 482 2012-01-05 23:27:27Z jhyde $ */ class DictionaryImpl & XmlaConstant> implements XmlaConstant.Dictionary { private final Class clazz; private final Map byName = new HashMap(); private final Map byOrdinal = new HashMap(); private List values; private static final Map map = new HashMap(); public DictionaryImpl(Class clazz) { this.clazz = clazz; init(); } private void init() { if (values != null) { // Already initialized. return; } // The following statement throws NullPointerException under JDK1.4 // (that is, when retrowoven) if clazz has not finished loading. This // happens when a static member of clazz is a Dictionary. If this // happens, swallow the NullPointerException and return null. init will // be called later. final E[] constants; try { constants = clazz.getEnumConstants(); } catch (NullPointerException e) { return; } this.values = Collections.unmodifiableList( Arrays.asList(constants)); for (E e : values) { byName.put(e.xmlaName(), e); byOrdinal.put(e.xmlaOrdinal(), e); } } public static & XmlaConstant> DictionaryImpl forClass( Class clazz) { assert clazz != null; synchronized (map) { @SuppressWarnings({"unchecked"}) DictionaryImpl directory = map.get(clazz); if (directory == null) { directory = new DictionaryImpl(clazz); map.put(clazz, directory); } return directory; } } public E forOrdinal(int xmlaOrdinal) { init(); return byOrdinal.get(xmlaOrdinal); } public E forName(String xmlaName) { init(); return byName.get(xmlaName); } public Set forMask( int xmlaOrdinalMask) { init(); Set set = Olap4jUtil.enumSetNoneOf(clazz); for (E e : values) { if ((xmlaOrdinalMask & e.xmlaOrdinal()) != 0) { set.add(e); } } return set; } public int toMask(Set set) { int mask = 0; for (E e : set) { mask |= e.xmlaOrdinal(); } return mask; } public List getValues() { init(); return values; } public Class getEnumClass() { return clazz; } } // End DictionaryImpl.java olap4j-1.0.1.500/src/org/olap4j/metadata/Measure.java0000644000175000017500000001034711707254772021715 0ustar drazzibdrazzib/* // $Id: Measure.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.metadata; /** * Data value of primary interest to the user browsing the cube. * *

A Measure provides the value of each cell, and is usually * numeric. Every measure is a member of a special dimension called "Measures". * * @author jhyde * @version $Id: Measure.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 13, 2006 */ public interface Measure extends Member { /** * Returns the Aggregator of this Measure. * * @return Aggregator */ Aggregator getAggregator(); /** * Returns the data type of this Measure. * * @return data type */ Datatype getDatatype(); /** * Returns whether this Measure is visible. * * @return whether this Measure is visible */ boolean isVisible(); /** * Enumeration of the aggregate functions which can be used to derive a * Measure. * *

The values are as specified by XMLA. * For example, XMLA specifies MDMEASURE_AGGR_SUM with ordinal 1, * which corresponds to the value {@link #SUM}, * whose {@link #xmlaOrdinal} is 1. */ enum Aggregator implements XmlaConstant { /** * Identifies that the measure was derived using the * SUM aggregation function. */ SUM(1), /** * Identifies that the measure was derived using the * COUNT aggregation function. */ COUNT(2), /** * Identifies that the measure was derived using the * MIN aggregation function. */ MIN(3), /** * Identifies that the measure was derived using the * MAX aggregation function. */ MAX(4), /** * Identifies that the measure was derived using the * AVG aggregation function. */ AVG(5), /** * Identifies that the measure was derived using the * VAR aggregation function. */ VAR(6), /** * Identifies that the measure was derived using the * STDEV aggregation function. */ STD(7), /** * Identifies that the measure was derived from a formula that was not * any single function above. */ CALCULATED(127), /** * Identifies that the measure was derived from an unknown aggregation * function or formula. */ UNKNOWN(0); private final int xmlaOrdinal; private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(Aggregator.class); /** * Creates an Aggregator. * * @param xmlaOrdinal Ordinal of the aggregator in the XMLA * specification */ private Aggregator(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } public String xmlaName() { return "MDMEASURE_AGGR_" + name(); } public String getDescription() { return ""; } public int xmlaOrdinal() { return xmlaOrdinal; } /** * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary * of all values of this enumeration. * * @return Dictionary of all values */ public static Dictionary getDictionary() { return DICTIONARY; } } } // End Measure.java olap4j-1.0.1.500/src/org/olap4j/CellSetListener.java0000644000175000017500000001674711707255012021573 0ustar drazzibdrazzib/* // $Id: CellSetListener.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import java.util.List; /** * Listener interface for receiving events when the contents of a * {@link CellSet} have changed. * *

NOTE: This functionality is experimental and is subject to change or * removal without notice. * *

The client can ask the server to provide the listener with a specific * {@link Granularity granularity} of events, but the server can decline to * provide that granularity. * *

Fine granularity deals with changes such as cell values changing (and * reports the before and after value, before and after formatted value), * positions being deleted, positions being changed. * *

When an atomic change happens on the server (say a cache flush, if the * server is mondrian) then an event will arrive on the client containing all of * those changes. Although {@link CellSetChange#getCellChanges} and * {@link CellSetChange#getAxisChanges} return lists, the client should assume * that all of the events in these lists simultaneously. * *

At any point, the server is free to throw up its hands and say 'there are * too many changes' by sending null values for {@code getCellChanges} or * {@code getAxisChanges}. This prevents situations where there are huge numbers * of changes that might overwhelm the server, the network link, or the client, * such as might happen if a large axis is re-sorted. * *

The client should always be ready for that to happen (even for providers * that claim to provide fine granularity events), and should re-execute the * query to get the cell set. In fact, we recommend that clients re-execute the * query to get a new cellset whenever they get an event. Then the client can * use the details in the event to highlight cells that have changed. * *

Notes for implementors

* *

The purpose of registering a listener before creating a cell set is to * ensure that no events "leak out" between creating a cell set and registering * a listener, or while a statement is being re-executed to produce a new cell * set. * *

The {@link #cellSetOpened(CellSet)} and {@link #cellSetClosed(CellSet)} * methods are provided so that the listener knows what is going on when a * statement is re-executed. In particular, suppose a statement receives an * change event decides to re-execute. The listener is attached to the * statement, so receives notifications about both old and new cell sets. The * driver implicitls closes the previous cell set and calls * {@code cellSetClosed}, then calls {@code cellSetOpened} with the new cell * set. * *

If changes are occurring regularly on the server, there will soon be a * call to {@link #cellSetChanged}. It is important to note that this event * contains only changes that have occurred since the new cell set was opened. * *

The granularity parameter is provided to {@link OlapStatement#addListener} * for the server's benefit. If granularity is only {@link Granularity#COARSE}, * the server may be able to store less information in order to track the cell * set. * * @version $Id: CellSetListener.java 482 2012-01-05 23:27:27Z jhyde $ */ public interface CellSetListener { /** * Invoked when a cell set is opened. * * @param cellSet Cell set */ void cellSetOpened(CellSet cellSet); /** * Invoked when a cell set is closed. * * @param cellSet Cell set */ void cellSetClosed(CellSet cellSet); /** * Invoked when a cell set has changed. * * @param cellSetChange Change descriptor */ void cellSetChanged(CellSetChange cellSetChange); /** * Granularity of notifications that should be sent to a cellset listener. */ enum Granularity { FINE, COARSE } /** * Description of changes that have occurred to the cell set. */ interface CellSetChange { /** * Returns the cell set affected by this change. * * @return Cell set affected by this change. */ CellSet getCellSet(); /** * Returns a list of cells that have changed, or null if the server * cannot provide detailed changes. * *

The server is always at liberty to provide a {@code CellSetChange} * without a detailed list of changes, even if * {@link Granularity#COARSE} was specified when the listener was * attached. Here are some typical reasons:

    * *
  • If there are very many changes. (Transmitting these changes over * the network would be costly, and the user interface also might * struggle to redisplay so many cells.) * *
  • If the axes have changed significantly. (If an axis position has * changed, all of the cells at that position will necssarily have * changed.) * *
  • If the client did not ask for detailed changes * *
  • If the the provider is not capable of giving detailed changes. *
*/ List getCellChanges(); /** * Returns a list of axis changes, or null if server cannot provide * detailed changes. * *

The reasons why this method returns null are similar to the * reasons why {@link #getCellChanges()} returns null. * * @return List of changes to positions on axes, or null if the server * cannot provide detailed changes. */ List getAxisChanges(); } /** * Description of a change to a particular {@link Cell}; part of a * {@link CellSetChange}. */ interface CellChange { /** * Returns the cell before the change. */ Cell getBeforeCell(); /** * Returns the cell after the change. */ Cell getAfterCell(); } /** * Description of a change to a particular {@link CellSetAxis}; part of a * {@link CellSetChange}. */ interface AxisChange { /** * Returns the axis affected by this change. * * @return Axis affected by this change */ CellSetAxis getAxis(); /** * Returns the position before the change. Null if the change created a * new position. * * @return Position before the change, or null if the position is newly * created */ Position getBeforePosition(); /** * Returns the position after the change. Null if the change deleted * this position. * * @return Position after the change, or null if the position is deleted */ Position getAfterPosition(); } } // End CellSetListener.java olap4j-1.0.1.500/src/org/olap4j/OlapWrapper.java0000644000175000017500000000615411707255012020755 0ustar drazzibdrazzib/* // $Id: OlapWrapper.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import java.sql.SQLException; /** * Interface for olap4j classes which provide the ability to retrieve the * delegate instance when the instance in question is in fact a proxy class. * *

OlapWrapper duplicates the functionality of the * java.sql.Wrapper interface (introduced in JDBC 4.0), making * this functionality available to olap4j clients running in a JDBC 3.0 * environment. For code which will run only on JDBC 4.0 and later, Wrapper can * be used, and OlapWrapper can be ignored.

* *

In JDBC 3.0 (JDK 1.5) and earlier, the OlapWrapper interface * is used to convert a JDBC class to the corresponding olap4j class. For * instance, write * *

*
 * import java.sql.Connection;
 * import java.sql.DriverManager;
 * import org.olap4j.OlapConnection;
 * import org.olap4j.OlapWrapper;
 *
 * Connection connection = DriverManager.getConnection("jdbc: ...");
 * OlapWrapper wrapper = (OlapWrapper) connection;
 * OlapConnection olapConnection = wrapper.unwrap(OlapConnection.class);
 * 
*
* * to create a JDBC 3.0 connection and convert it to an olap4j connection. * *

In JDBC 4.0 (JDK 1.6) and later, you don't need to use this class. All of * the key JDBC classes implement java.sql.Wrapper interface, so * you can use its isWrapper and unwrap methods * without casting. For instance, write * *

*
 * import java.sql.Connection;
 * import java.sql.DriverManager;
 * import org.olap4j.OlapConnection;
 *
 * Connection connection = DriverManager.getConnection("jdbc: ...");
 * OlapConnection olapConnection = connection.unwrap(OlapConnection.class);
 * 
*
* * to create a JDBC 4.0 connection and convert it to an olap4j connection. * * @author jhyde * @version $Id: OlapWrapper.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 14, 2007 */ public interface OlapWrapper { // duplicate method from java.sql.Wrapper (JDBC 4.0), so method is available // in JDBC 3.0 T unwrap(Class iface) throws SQLException; // duplicate method from java.sql.Wrapper (JDBC 4.0), so method is available // in JDBC 3.0 boolean isWrapperFor(Class iface) throws SQLException; } // End OlapWrapper.java olap4j-1.0.1.500/src/org/olap4j/driver/0000755000175000017500000000000011421322450017135 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/driver/xmla/0000755000175000017500000000000011713757640020117 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jUtil.java0000644000175000017500000004265411707255006023576 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jUtil.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.apache.xerces.impl.Constants; import org.apache.xerces.parsers.DOMParser; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.w3c.dom.*; import org.xml.sax.*; import java.io.*; import java.util.*; /** * Utility methods for the olap4j driver for XML/A. * *

Many of the methods are related to XML parsing. For general-purpose * methods useful for implementing any olap4j driver, see the org.olap4j.impl * package and in particular {@link org.olap4j.impl.Olap4jUtil}. * * @author jhyde * @version $Id: XmlaOlap4jUtil.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 2, 2007 */ abstract class XmlaOlap4jUtil { static final String LINE_SEP = System.getProperty("line.separator", "\n"); static final String SOAP_PREFIX = "SOAP-ENV"; static final String SOAP_NS = "http://schemas.xmlsoap.org/soap/envelope/"; static final String XMLA_PREFIX = "xmla"; static final String XMLA_NS = "urn:schemas-microsoft-com:xml-analysis"; static final String MDDATASET_NS = "urn:schemas-microsoft-com:xml-analysis:mddataset"; static final String ROWSET_NS = "urn:schemas-microsoft-com:xml-analysis:rowset"; static final String XSD_PREFIX = "xsd"; static final String XMLNS = "xmlns"; static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; static final String FULL_SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking"; static final String DEFER_NODE_EXPANSION = "http://apache.org/xml/features/dom/defer-node-expansion"; static final String SCHEMA_LOCATION = Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; /** * Parse a stream into a Document (no validation). * */ static Document parse(byte[] in) throws SAXException, IOException { InputSource source = new InputSource(new ByteArrayInputStream(in)); DOMParser parser = getParser(null, null, false); try { parser.parse(source); checkForParseError(parser); } catch (SAXParseException ex) { checkForParseError(parser, ex); } return parser.getDocument(); } /** * Get your non-cached DOM parser which can be configured to do schema * based validation of the instance Document. * */ static DOMParser getParser( String schemaLocationPropertyValue, EntityResolver entityResolver, boolean validate) throws SAXNotRecognizedException, SAXNotSupportedException { boolean doingValidation = (validate || (schemaLocationPropertyValue != null)); DOMParser parser = new DOMParser(); parser.setEntityResolver(entityResolver); parser.setErrorHandler(new ErrorHandlerImpl()); parser.setFeature(DEFER_NODE_EXPANSION, false); parser.setFeature(NAMESPACES_FEATURE_ID, true); parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, doingValidation); parser.setFeature(VALIDATION_FEATURE_ID, doingValidation); if (schemaLocationPropertyValue != null) { parser.setProperty( SCHEMA_LOCATION, schemaLocationPropertyValue.replace('\\', '/')); } return parser; } /** * Checks whether the DOMParser after parsing a Document has any errors and, * if so, throws a RuntimeException exception containing the errors. */ static void checkForParseError(DOMParser parser, Throwable t) { final ErrorHandler errorHandler = parser.getErrorHandler(); if (errorHandler instanceof ErrorHandlerImpl) { final ErrorHandlerImpl saxEH = (ErrorHandlerImpl) errorHandler; final List errors = saxEH.getErrors(); if (errors != null && errors.size() > 0) { String errorStr = ErrorHandlerImpl.formatErrorInfos(saxEH); throw new RuntimeException(errorStr, t); } } else { System.out.println("errorHandler=" + errorHandler); } } static void checkForParseError(final DOMParser parser) { checkForParseError(parser, null); } static List listOf(final NodeList nodeList) { return new AbstractList() { public Node get(int index) { return nodeList.item(index); } public int size() { return nodeList.getLength(); } }; } static String gatherText(Element element) { StringBuilder buf = new StringBuilder(); final NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { buf.append(childNodes.item(i).getTextContent()); } return buf.toString(); } static String prettyPrint(Element element) { StringBuilder string = new StringBuilder(); prettyPrintLoop(element, string, ""); return string.toString(); } private static void prettyPrintLoop( NodeList nodes, StringBuilder string, String indentation) { for (int index = 0; index < nodes.getLength(); index++) { prettyPrintLoop(nodes.item(index), string, indentation); } } private static void prettyPrintLoop( Node node, StringBuilder string, String indentation) { if (node == null) { return; } int type = node.getNodeType(); switch (type) { case Node.DOCUMENT_NODE: string.append("\n"); prettyPrintLoop(node.getChildNodes(), string, indentation + "\t"); break; case Node.ELEMENT_NODE: string.append(indentation); string.append("<"); string.append(node.getNodeName()); Attr[] attributes; if (node.getAttributes() != null) { int length = node.getAttributes().getLength(); attributes = new Attr[length]; for (int loopIndex = 0; loopIndex < length; loopIndex++) { attributes[loopIndex] = (Attr)node.getAttributes().item(loopIndex); } } else { attributes = new Attr[0]; } for (Attr attribute : attributes) { string.append(" "); string.append(attribute.getNodeName()); string.append("=\""); string.append(attribute.getNodeValue()); string.append("\""); } string.append(">\n"); prettyPrintLoop(node.getChildNodes(), string, indentation + "\t"); string.append(indentation); string.append("\n"); break; case Node.TEXT_NODE: string.append(indentation); string.append(node.getNodeValue().trim()); string.append("\n"); break; case Node.PROCESSING_INSTRUCTION_NODE: string.append(indentation); string.append(" 0) { string.append(text); } string.append("?>\n"); break; case Node.CDATA_SECTION_NODE: string.append(indentation); string.append(""); break; } } static Element findChild(Element element, String ns, String tag) { final NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { if (childNodes.item(i) instanceof Element) { Element child = (Element) childNodes.item(i); if (child.getLocalName().equals(tag) && (ns == null || child.getNamespaceURI().equals(ns))) { return child; } } } return null; } static String stringElement(Element row, String name) { final NodeList childNodes = row.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { final Node node = childNodes.item(i); if (name.equals(node.getLocalName())) { return node.getTextContent(); } } return null; } static Integer integerElement(Element row, String name) { final String s = stringElement(row, name); if (s == null || s.equals("")) { return null; } else { return Integer.valueOf(s); } } static int intElement(Element row, String name) { return integerElement(row, name).intValue(); } static Double doubleElement(Element row, String name) { return Double.valueOf(stringElement(row, name)); } static boolean booleanElement(Element row, String name) { return "true".equals(stringElement(row, name)); } static Float floatElement(Element row, String name) { return Float.valueOf(stringElement(row, name)); } static long longElement(Element row, String name) { return Long.valueOf(stringElement(row, name)).longValue(); } static List childElements(Element memberNode) { final List list = new ArrayList(); final NodeList childNodes = memberNode.getChildNodes(); for (int i = 0; i < childNodes.getLength(); ++i) { final Node childNode = childNodes.item(i); if (childNode instanceof Element) { list.add((Element) childNode); } } return list; } static List findChildren(Element element, String ns, String tag) { final List list = new ArrayList(); for (Node node : listOf(element.getChildNodes())) { if (tag.equals(node.getLocalName()) && ((ns == null) || node.getNamespaceURI().equals(ns))) { list.add((Element) node); } } return list; } /** * Converts a Node to a String. * * @param node XML node * @param prettyPrint Whether to print with nice indentation * @return String representation of XML */ public static String toString(Node node, boolean prettyPrint) { if (node == null) { return null; } try { Document doc = node.getOwnerDocument(); OutputFormat format; if (doc != null) { format = new OutputFormat(doc, null, prettyPrint); } else { format = new OutputFormat("xml", null, prettyPrint); } if (prettyPrint) { format.setLineSeparator(LINE_SEP); } else { format.setLineSeparator(""); } StringWriter writer = new StringWriter(1000); XMLSerializer serial = new XMLSerializer(writer, format); serial.asDOMSerializer(); if (node instanceof Document) { serial.serialize((Document) node); } else if (node instanceof Element) { format.setOmitXMLDeclaration(true); serial.serialize((Element) node); } else if (node instanceof DocumentFragment) { format.setOmitXMLDeclaration(true); serial.serialize((DocumentFragment) node); } else if (node instanceof Text) { Text text = (Text) node; return text.getData(); } else if (node instanceof Attr) { Attr attr = (Attr) node; String name = attr.getName(); String value = attr.getValue(); writer.write(name); writer.write("=\""); writer.write(value); writer.write("\""); if (prettyPrint) { writer.write(LINE_SEP); } } else { writer.write("node class = " + node.getClass().getName()); if (prettyPrint) { writer.write(LINE_SEP); } else { writer.write(' '); } writer.write("XmlUtil.toString: fix me: "); writer.write(node.toString()); if (prettyPrint) { writer.write(LINE_SEP); } } return writer.toString(); } catch (Exception ex) { // ignore return null; } } /** * Error handler plus helper methods. */ static class ErrorHandlerImpl implements ErrorHandler { public static final String WARNING_STRING = "WARNING"; public static final String ERROR_STRING = "ERROR"; public static final String FATAL_ERROR_STRING = "FATAL"; // DOMError values public static final short SEVERITY_WARNING = 1; public static final short SEVERITY_ERROR = 2; public static final short SEVERITY_FATAL_ERROR = 3; public void printErrorInfos(PrintStream out) { if (errors != null) { for (ErrorInfo error : errors) { out.println(formatErrorInfo(error)); } } } public static String formatErrorInfos(ErrorHandlerImpl saxEH) { if (! saxEH.hasErrors()) { return ""; } StringBuilder buf = new StringBuilder(512); for (ErrorInfo error : saxEH.getErrors()) { buf.append(formatErrorInfo(error)); buf.append(LINE_SEP); } return buf.toString(); } public static String formatErrorInfo(ErrorInfo ei) { StringBuilder buf = new StringBuilder(128); buf.append("["); switch (ei.severity) { case SEVERITY_WARNING: buf.append(WARNING_STRING); break; case SEVERITY_ERROR: buf.append(ERROR_STRING); break; case SEVERITY_FATAL_ERROR: buf.append(FATAL_ERROR_STRING); break; } buf.append(']'); String systemId = ei.exception.getSystemId(); if (systemId != null) { int index = systemId.lastIndexOf('/'); if (index != -1) { systemId = systemId.substring(index + 1); } buf.append(systemId); } buf.append(':'); buf.append(ei.exception.getLineNumber()); buf.append(':'); buf.append(ei.exception.getColumnNumber()); buf.append(": "); buf.append(ei.exception.getMessage()); return buf.toString(); } private List errors; public ErrorHandlerImpl() { } public List getErrors() { return this.errors; } public boolean hasErrors() { return (this.errors != null); } public void warning(SAXParseException exception) throws SAXException { addError(new ErrorInfo(SEVERITY_WARNING, exception)); } public void error(SAXParseException exception) throws SAXException { addError(new ErrorInfo(SEVERITY_ERROR, exception)); } public void fatalError(SAXParseException exception) throws SAXException { addError(new ErrorInfo(SEVERITY_FATAL_ERROR, exception)); } protected void addError(ErrorInfo ei) { if (this.errors == null) { this.errors = new ArrayList(); } this.errors.add(ei); } public String getFirstError() { return (hasErrors()) ? formatErrorInfo(errors.get(0)) : ""; } } static class ErrorInfo { final SAXParseException exception; final short severity; ErrorInfo(short severity, SAXParseException exception) { this.severity = severity; this.exception = exception; } } } // End XmlaOlap4jUtil.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jDimension.java0000644000175000017500000000730011707255006024573 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jDimension.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.Named; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; /** * Implementation of {@link org.olap4j.metadata.Dimension} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jDimension.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 4, 2007 */ class XmlaOlap4jDimension extends XmlaOlap4jElement implements Dimension, Named { final XmlaOlap4jCube olap4jCube; final Type type; final NamedList hierarchies; private final String defaultHierarchyUniqueName; private final int ordinal; XmlaOlap4jDimension( XmlaOlap4jCube olap4jCube, String uniqueName, String name, String caption, String description, Type type, String defaultHierarchyUniqueName, int ordinal) { super(uniqueName, name, caption, description); this.defaultHierarchyUniqueName = defaultHierarchyUniqueName; assert olap4jCube != null; this.olap4jCube = olap4jCube; this.type = type; this.ordinal = ordinal; String[] dimensionRestrictions = { "CATALOG_NAME", olap4jCube.olap4jSchema.olap4jCatalog.getName(), "SCHEMA_NAME", olap4jCube.olap4jSchema.getName(), "CUBE_NAME", olap4jCube.getName(), "DIMENSION_UNIQUE_NAME", getUniqueName() }; this.hierarchies = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_HIERARCHIES, new XmlaOlap4jConnection.Context( olap4jCube.olap4jSchema.olap4jCatalog .olap4jDatabaseMetaData.olap4jConnection, olap4jCube.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData, olap4jCube.olap4jSchema.olap4jCatalog, olap4jCube.olap4jSchema, olap4jCube, this, null, null), new XmlaOlap4jConnection.HierarchyHandler(olap4jCube), dimensionRestrictions); } public NamedList getHierarchies() { return Olap4jUtil.cast(hierarchies); } public Type getDimensionType() throws OlapException { return type; } public Hierarchy getDefaultHierarchy() { for (XmlaOlap4jHierarchy hierarchy : hierarchies) { if (hierarchy.getUniqueName().equals(defaultHierarchyUniqueName)) { return hierarchy; } } return hierarchies.get(0); } public boolean equals(Object obj) { return (obj instanceof XmlaOlap4jDimension) && this.uniqueName.equals( ((XmlaOlap4jDimension) obj).getUniqueName()); } public int getOrdinal() { return ordinal; } } // End XmlaOlap4jDimension.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java0000644000175000017500000002573111707255006024065 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jMember.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.*; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.*; import java.util.*; /** * Implementation of {@link org.olap4j.metadata.Member} * for XML/A providers. * *

TODO:

    *
  1. create members with a pointer to their parent member (not the name)
  2. *
  3. implement a member cache (by unique name, belongs to cube, soft)
  4. *
  5. implement Hierarchy.getRootMembers
  6. *
* * @author jhyde * @version $Id: XmlaOlap4jMember.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 5, 2007 */ class XmlaOlap4jMember extends XmlaOlap4jElement implements XmlaOlap4jMemberBase, Member, Named { private final XmlaOlap4jLevel olap4jLevel; // TODO: We would rather have a refernce to the parent member, but it is // tricky to populate /* private final XmlaOlap4jMember parentMember; */ private final String parentMemberUniqueName; private final Type type; private XmlaOlap4jMember parentMember; private final int childMemberCount; private final int ordinal; private final Map propertyValueMap; /** * Creates an XmlaOlap4jMember. * * @param olap4jLevel Level * @param uniqueName Unique name * @param name Name * @param caption Caption * @param description Description * @param parentMemberUniqueName Unique name of parent, or null if no parent * @param type Type * @param childMemberCount Number of children * @param ordinal Ordinal in its hierarchy * @param propertyValueMap Property values */ XmlaOlap4jMember( XmlaOlap4jLevel olap4jLevel, String uniqueName, String name, String caption, String description, String parentMemberUniqueName, Type type, int childMemberCount, int ordinal, Map propertyValueMap) { super(uniqueName, name, caption, description); this.ordinal = ordinal; assert olap4jLevel != null; assert type != null; this.olap4jLevel = olap4jLevel; this.parentMemberUniqueName = parentMemberUniqueName; this.type = type; this.childMemberCount = childMemberCount; this.propertyValueMap = UnmodifiableArrayMap.of(propertyValueMap); } public int hashCode() { return uniqueName.hashCode(); } public boolean equals(Object obj) { return obj instanceof XmlaOlap4jMember && ((XmlaOlap4jMember) obj).uniqueName.equals(uniqueName); } public NamedList getChildMembers() throws OlapException { final NamedList list = new NamedListImpl(); getCube() .getMetadataReader() .lookupMemberRelatives( Olap4jUtil.enumSetOf(TreeOp.CHILDREN), uniqueName, list); return list; } public int getChildMemberCount() { return childMemberCount; } public XmlaOlap4jMember getParentMember() { if (parentMemberUniqueName == null) { return null; } if (parentMember == null) { try { parentMember = getCube().getMetadataReader() .lookupMemberByUniqueName(parentMemberUniqueName); } catch (OlapException e) { throw new RuntimeException("yuck!"); // FIXME } } return parentMember; } public XmlaOlap4jLevel getLevel() { return olap4jLevel; } public XmlaOlap4jHierarchy getHierarchy() { return olap4jLevel.olap4jHierarchy; } public XmlaOlap4jDimension getDimension() { return olap4jLevel.olap4jHierarchy.olap4jDimension; } public Type getMemberType() { return type; } public boolean isAll() { return type == Type.ALL; } public boolean isChildOrEqualTo(Member member) { throw new UnsupportedOperationException(); } public boolean isCalculated() { return type == Type.FORMULA; } public int getSolveOrder() { throw new UnsupportedOperationException(); } public ParseTreeNode getExpression() { throw new UnsupportedOperationException(); } public List getAncestorMembers() { final List list = new ArrayList(); XmlaOlap4jMember m = getParentMember(); while (m != null) { list.add(m); m = m.getParentMember(); } return list; } public boolean isCalculatedInQuery() { throw new UnsupportedOperationException(); } public Object getPropertyValue(Property property) throws OlapException { return getPropertyValue( property, this, propertyValueMap); } /** * Helper method to retrieve the value of a property from a member. * * @param property Property * @param member Member * @param propertyValueMap Map of property-value pairs * @return Property value * * @throws OlapException if database error occurs while evaluating * CHILDREN_CARDINALITY; no other property throws */ static Object getPropertyValue( Property property, XmlaOlap4jMemberBase member, Map propertyValueMap) throws OlapException { // If property map contains a value for this property (even if that // value is null), that overrides. final Object value = propertyValueMap.get(property); if (value != null || propertyValueMap.containsKey(property)) { return value; } if (property instanceof Property.StandardMemberProperty) { Property.StandardMemberProperty o = (Property.StandardMemberProperty) property; switch (o) { case MEMBER_CAPTION: return member.getCaption(); case MEMBER_NAME: return member.getName(); case MEMBER_UNIQUE_NAME: return member.getUniqueName(); case CATALOG_NAME: return member.getCatalog().getName(); case CHILDREN_CARDINALITY: return member.getChildMemberCount(); case CUBE_NAME: return member.getCube().getName(); case DEPTH: return member.getDepth(); case DESCRIPTION: return member.getDescription(); case DIMENSION_UNIQUE_NAME: return member.getDimension().getUniqueName(); case DISPLAY_INFO: // TODO: return null; case HIERARCHY_UNIQUE_NAME: return member.getHierarchy().getUniqueName(); case LEVEL_NUMBER: return member.getLevel().getDepth(); case LEVEL_UNIQUE_NAME: return member.getLevel().getUniqueName(); case MEMBER_GUID: // TODO: return null; case MEMBER_ORDINAL: return member.getOrdinal(); case MEMBER_TYPE: return member.getMemberType(); case PARENT_COUNT: return 1; case PARENT_LEVEL: return member.getParentMember() == null ? 0 : member.getParentMember().getLevel().getDepth(); case PARENT_UNIQUE_NAME: return member.getParentMember() == null ? null : member.getParentMember().getUniqueName(); case SCHEMA_NAME: return member.getCube().olap4jSchema.getName(); case VALUE: // TODO: return null; } } return null; } // convenience method - not part of olap4j API public XmlaOlap4jCube getCube() { return olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube; } // convenience method - not part of olap4j API public XmlaOlap4jCatalog getCatalog() { return olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema.olap4jCatalog; } // convenience method - not part of olap4j API public XmlaOlap4jConnection getConnection() { return olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection; } // convenience method - not part of olap4j API public Map getPropertyValueMap() { return propertyValueMap; } public String getPropertyFormattedValue(Property property) throws OlapException { // FIXME: need to use a format string; but what format string; and how // to format the property on the client side? return String.valueOf(getPropertyValue(property)); } public void setProperty(Property property, Object value) { propertyValueMap.put(property, value); } public NamedList getProperties() { return olap4jLevel.getProperties(); } public int getOrdinal() { return ordinal; } public boolean isHidden() { throw new UnsupportedOperationException(); } public int getDepth() { // Since in regular hierarchies members have the same depth as their // level, we store depth as a property only where it is different. final Object depth = propertyValueMap.get(Property.StandardMemberProperty.DEPTH); if (depth == null) { return olap4jLevel.getDepth(); } else { return toInteger(depth); } } /** * Converts an object to an integer value. Must not be null. * * @param o Object * @return Integer value */ static int toInteger(Object o) { if (o instanceof Number) { Number number = (Number) o; return number.intValue(); } return Integer.valueOf(o.toString()); } public Member getDataMember() { throw new UnsupportedOperationException(); } } // End XmlaOlap4jMember.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMemberProperty.java0000644000175000017500000000435711707255006027107 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCellSetMemberProperty.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.impl.Named; import org.olap4j.metadata.*; import java.util.Set; /** * Implementation of {@link org.olap4j.metadata.Property} * for a member returned on an axis in a cellset * from an XML/A provider. * * @author jhyde * @version $Id: XmlaOlap4jCellSetMemberProperty.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 7, 2007 */ class XmlaOlap4jCellSetMemberProperty implements Property, Named { private final String propertyUniqueName; final Hierarchy hierarchy; final String tag; XmlaOlap4jCellSetMemberProperty( String propertyUniqueName, Hierarchy hierarchy, String tag) { this.propertyUniqueName = propertyUniqueName; this.hierarchy = hierarchy; this.tag = tag; } public Datatype getDatatype() { return Datatype.STRING; } public Set getType() { return TypeFlag.MEMBER_TYPE_FLAG; } public String getName() { return tag; } public String getUniqueName() { return propertyUniqueName; } public String getCaption() { return propertyUniqueName; } public String getDescription() { return ""; } public ContentType getContentType() { return ContentType.REGULAR; } public boolean isVisible() { return true; } } // End XmlaOlap4jCellSetMemberProperty.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/FactoryJdbc41Impl.java0000644000175000017500000002002611707255006024133 0ustar drazzibdrazzib/* // $Id: FactoryJdbc41Impl.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import java.sql.*; import java.util.*; import java.util.concurrent.Executor; /** * Implementation of {@link Factory} for JDBC 4.0. * * @author jhyde * @version $Id: FactoryJdbc41Impl.java 483 2012-01-05 23:43:18Z jhyde $ * @since Jun 14, 2007 */ class FactoryJdbc41Impl implements Factory { /** * Creates a FactoryJdbc41Impl. */ public FactoryJdbc41Impl() { } public Connection newConnection( XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { return new XmlaOlap4jConnectionJdbc41( this, driver, proxy, url, info); } public EmptyResultSet newEmptyResultSet( XmlaOlap4jConnection olap4jConnection) { List headerList = Collections.emptyList(); List> rowList = Collections.emptyList(); return new EmptyResultSetJdbc41(olap4jConnection, headerList, rowList); } public ResultSet newFixedResultSet( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { return new EmptyResultSetJdbc41( olap4jConnection, headerList, rowList); } public XmlaOlap4jCellSet newCellSet( XmlaOlap4jStatement olap4jStatement) throws OlapException { return new XmlaOlap4jCellSetJdbc41(olap4jStatement); } public XmlaOlap4jStatement newStatement( XmlaOlap4jConnection olap4jConnection) { return new XmlaOlap4jStatementJdbc41(olap4jConnection); } public XmlaOlap4jPreparedStatement newPreparedStatement( String mdx, XmlaOlap4jConnection olap4jConnection) throws OlapException { return new XmlaOlap4jPreparedStatementJdbc41(olap4jConnection, mdx); } public XmlaOlap4jDatabaseMetaData newDatabaseMetaData( XmlaOlap4jConnection olap4jConnection) { return new XmlaOlap4jDatabaseMetaDataJdbc41(olap4jConnection); } // Inner classes private static class EmptyResultSetJdbc41 extends FactoryJdbc4Plus.AbstractEmptyResultSet { /** * Creates a EmptyResultSetJdbc41. * * @param olap4jConnection Connection * @param headerList Column names * @param rowList List of row values */ EmptyResultSetJdbc41( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { super(olap4jConnection, headerList, rowList); } public T getObject( int columnIndex, Class type) throws SQLException { throw new UnsupportedOperationException(); } public T getObject( String columnLabel, Class type) throws SQLException { throw new UnsupportedOperationException(); } } private static class XmlaOlap4jConnectionJdbc41 extends FactoryJdbc4Plus.AbstractConnection { /** * Creates a XmlaOlap4jConnectionJdbc41. * * @param factory Factory * @param driver Driver * @param proxy Proxy * @param url URL * @param info Extra properties * @throws SQLException on error */ public XmlaOlap4jConnectionJdbc41( Factory factory, XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { super(factory, driver, proxy, url, info); } public void abort(Executor executor) throws SQLException { throw new UnsupportedOperationException(); } public void setNetworkTimeout( Executor executor, int milliseconds) throws SQLException { throw new UnsupportedOperationException(); } public int getNetworkTimeout() throws SQLException { throw new UnsupportedOperationException(); } } private static class XmlaOlap4jCellSetJdbc41 extends FactoryJdbc4Plus.AbstractCellSet { /** * Creates an XmlaOlap4jCellSetJdbc41. * * @param olap4jStatement Statement * @throws OlapException on error */ XmlaOlap4jCellSetJdbc41( XmlaOlap4jStatement olap4jStatement) throws OlapException { super(olap4jStatement); } public T getObject( int columnIndex, Class type) throws SQLException { throw new UnsupportedOperationException(); } public T getObject( String columnLabel, Class type) throws SQLException { throw new UnsupportedOperationException(); } } private static class XmlaOlap4jStatementJdbc41 extends XmlaOlap4jStatement { /** * Creates a XmlaOlap4jStatementJdbc41. * * @param olap4jConnection Connection */ XmlaOlap4jStatementJdbc41( XmlaOlap4jConnection olap4jConnection) { super(olap4jConnection); } public void closeOnCompletion() throws SQLException { throw new UnsupportedOperationException(); } public boolean isCloseOnCompletion() throws SQLException { throw new UnsupportedOperationException(); } } private static class XmlaOlap4jPreparedStatementJdbc41 extends FactoryJdbc4Plus.AbstractPreparedStatement { /** * Creates a XmlaOlap4jPreparedStatementJdbc41. * * @param olap4jConnection Connection * @param mdx MDX query text * @throws OlapException on error */ XmlaOlap4jPreparedStatementJdbc41( XmlaOlap4jConnection olap4jConnection, String mdx) throws OlapException { super(olap4jConnection, mdx); } public void closeOnCompletion() throws SQLException { throw new UnsupportedOperationException(); } public boolean isCloseOnCompletion() throws SQLException { throw new UnsupportedOperationException(); } } private static class XmlaOlap4jDatabaseMetaDataJdbc41 extends FactoryJdbc4Plus.AbstractDatabaseMetaData { /** * Creates an XmlaOlap4jDatabaseMetaDataJdbc41. * * @param olap4jConnection Connection */ XmlaOlap4jDatabaseMetaDataJdbc41( XmlaOlap4jConnection olap4jConnection) { super(olap4jConnection); } public ResultSet getPseudoColumns( String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public boolean generatedKeyAlwaysReturned() throws SQLException { throw new UnsupportedOperationException(); } } } // End FactoryJdbc41Impl.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jDriverVersion.java0000644000175000017500000000072111713757640025457 0ustar drazzibdrazzib/* * Project version information. Generated - do not modify. */ package org.olap4j.driver.xmla; /** * Version information for the XMLA driver. (Generated.) */ class XmlaOlap4jDriverVersion { static final String NAME = "olap4j driver for XML/A"; static final String VERSION = "1.0.1.500"; static final int MAJOR_VERSION = Integer.valueOf("1"); static final int MINOR_VERSION = Integer.valueOf("00010500"); } // End XmlaOlap4jDriverVersion.javaolap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetAxis.java0000644000175000017500000000477611707255006025044 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCellSetAxis.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import java.util.List; import java.util.ListIterator; /** * Implementation of {@link org.olap4j.CellSetAxis} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jCellSetAxis.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 5, 2007 */ class XmlaOlap4jCellSetAxis implements CellSetAxis { private final XmlaOlap4jCellSet olap4jCellSet; private final Axis axis; final List positions; /** * Creates an XmlaOlap4jCellSetAxis. * * @param olap4jCellSet Cell set * @param axis Axis identifier * @param positions List of positions. Caller must ensure it is immutable */ public XmlaOlap4jCellSetAxis( XmlaOlap4jCellSet olap4jCellSet, Axis axis, List positions) { this.olap4jCellSet = olap4jCellSet; this.axis = axis; this.positions = positions; } public Axis getAxisOrdinal() { return axis; } public CellSet getCellSet() { return olap4jCellSet; } public CellSetAxisMetaData getAxisMetaData() { final CellSetMetaData cellSetMetaData = olap4jCellSet.getMetaData(); if (axis.isFilter()) { return cellSetMetaData.getFilterAxisMetaData(); } else { return cellSetMetaData.getAxesMetaData().get( axis.axisOrdinal()); } } public List getPositions() { return positions; } public int getPositionCount() { return positions.size(); } public ListIterator iterator() { return positions.listIterator(); } } // End XmlaOlap4jCellSetAxis.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/MetadataReader.java0000644000175000017500000000605011707255006023616 0ustar drazzibdrazzib/* // $Id: MetadataReader.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.metadata.Member; import java.util.*; /** * Can read metadata, in particular members. * * @author jhyde * @version $Id: MetadataReader.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jan 14, 2008 */ interface MetadataReader { /** * Looks up a member by its unique name. * *

Not part of public olap4j API. * * @param memberUniqueName Unique name of member * @return Member, or null if not found * @throws org.olap4j.OlapException if error occurs */ XmlaOlap4jMember lookupMemberByUniqueName( String memberUniqueName) throws OlapException; /** * Looks up a list of members by their unique name and writes the results * into a map. * *

Not part of public olap4j API. * * @param memberUniqueNames List of unique names of member * * @param memberMap Map to populate with members * * @throws org.olap4j.OlapException if error occurs */ void lookupMembersByUniqueName( List memberUniqueNames, Map memberMap) throws OlapException; /** * Looks a member by its unique name and returns members related by * the specified tree-operations. * *

Not part of public olap4j API. * * @param memberUniqueName Unique name of member * * @param treeOps Collection of tree operations to travel relative to * given member in order to create list of members * * @param list list to be populated with members related to the given * member, or empty set if the member is not found * * @throws org.olap4j.OlapException if error occurs */ void lookupMemberRelatives( Set treeOps, String memberUniqueName, List list) throws OlapException; /** * Looks up members of a given level. * * @param level Level * * @throws org.olap4j.OlapException if error occurs * * @return list of members at in the level */ List getLevelMembers(XmlaOlap4jLevel level) throws OlapException; } // End MetadataReader.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/package.html0000644000175000017500000000010211421322452022352 0ustar drazzibdrazzib olap4j to XML for Analysis bridge. olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java0000644000175000017500000026351411713757476024777 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jConnection.java 499 2012-02-06 16:06:29Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import org.olap4j.driver.xmla.proxy.*; import org.olap4j.impl.*; import org.olap4j.mdx.ParseTreeWriter; import org.olap4j.mdx.SelectNode; import org.olap4j.mdx.parser.*; import org.olap4j.mdx.parser.impl.DefaultMdxParserImpl; import org.olap4j.metadata.*; import org.olap4j.metadata.Database.AuthenticationMode; import org.olap4j.metadata.Database.ProviderType; import org.w3c.dom.*; import org.xml.sax.SAXException; import java.io.IOException; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import java.sql.*; import java.util.*; import java.util.Map.Entry; import java.util.regex.Pattern; import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; /** * Implementation of {@link org.olap4j.OlapConnection} * for XML/A providers. * *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; * it is instantiated using {@link Factory#newConnection}.

* * @author jhyde * @version $Id: XmlaOlap4jConnection.java 499 2012-02-06 16:06:29Z lucboudreau $ * @since May 23, 2007 */ abstract class XmlaOlap4jConnection implements OlapConnection { /** * Handler for errors. */ final XmlaHelper helper = new XmlaHelper(); /** *

Current database. */ private XmlaOlap4jDatabase olap4jDatabase; /** *

Current catalog. */ private XmlaOlap4jCatalog olap4jCatalog; /** *

Current schema. */ private XmlaOlap4jSchema olap4jSchema; final XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData; private static final String CONNECT_STRING_PREFIX = "jdbc:xmla:"; final XmlaOlap4jDriver driver; final Factory factory; final XmlaOlap4jProxy proxy; private boolean closed = false; /** * URL of the HTTP server to which to send XML requests. */ final XmlaOlap4jServerInfos serverInfos; private Locale locale; /** * Name of the catalog to which the user wishes to bind * this connection. This value can be set through the JDBC URL * or via {@link XmlaOlap4jConnection#setCatalog(String)} */ private String catalogName; /** * Name of the schema to which the user wishes to bind * this connection to. This value can also be set through the * JDBC URL or via {@link XmlaOlap4jConnection#setSchema(String)} */ private String schemaName; /** * Name of the role that this connection impersonates. */ private String roleName; /** * Name of the database to which the user wishes to bind * this connection. This value can be set through the JDBC URL * or via {@link XmlaOlap4jConnection#setCatalog(String)} */ private String databaseName; /** * List of additional properties being used as part of the XML/A * calls as part of <PropertyList/>.
* Can be passed to connection via connection string properties. */ private final Map databaseProperties; private boolean autoCommit; private boolean readOnly; /** * Root of the metadata hierarchy of this connection. */ private final NamedList olapDatabases; private final URL serverUrlObject; /** * This is a private property used for development only. * Enabling it makes the connection print out all queries * to {@link System#out} */ private static final boolean DEBUG = false; /** * Creates an Olap4j connection an XML/A provider. * *

This method is intentionally package-protected. The public API * uses the traditional JDBC {@link java.sql.DriverManager}. * See {@link org.olap4j.driver.xmla.XmlaOlap4jDriver} for more details. * *

Note that this constructor should make zero non-trivial calls, which * could cause deadlocks due to java.sql.DriverManager synchronization * issues. * * @pre acceptsURL(url) * * @param factory Factory * @param driver Driver * @param proxy Proxy object which receives XML requests * @param url Connect-string URL * @param info Additional properties * @throws java.sql.SQLException if there is an error */ XmlaOlap4jConnection( Factory factory, XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { if (!acceptsURL(url)) { // This is not a URL we can handle. // DriverManager should not have invoked us. throw new AssertionError( "does not start with '" + CONNECT_STRING_PREFIX + "'"); } this.factory = factory; this.driver = driver; this.proxy = proxy; final Map map = parseConnectString(url, info); this.databaseProperties = new HashMap(); for (String infoKey : map.keySet()) { databaseProperties.put(infoKey, map.get(infoKey)); } this.databaseName = map.get(XmlaOlap4jDriver.Property.DATABASE.name()); this.catalogName = map.get(XmlaOlap4jDriver.Property.CATALOG.name()); this.schemaName = map.get(XmlaOlap4jDriver.Property.SCHEMA.name()); this.roleName = map.get(XmlaOlap4jDriver.Property.ROLE.name()); // Set URL of HTTP server. final String serverUrl = map.get(XmlaOlap4jDriver.Property.SERVER.name()); if (serverUrl == null) { throw getHelper().createException( "Connection property '" + XmlaOlap4jDriver.Property.SERVER.name() + "' must be specified"); } try { this.serverUrlObject = new URL(serverUrl); } catch (MalformedURLException e) { throw getHelper().createException(e); } // Initialize the SOAP cache if needed initSoapCache(map); this.serverInfos = new XmlaOlap4jServerInfos() { private String sessionId = null; public String getUsername() { return map.get( XmlaOlap4jDriver.Property.USER.name()); } public String getPassword() { return map.get( XmlaOlap4jDriver.Property.PASSWORD.name()); } public URL getUrl() { return serverUrlObject; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } }; this.olap4jDatabaseMetaData = factory.newDatabaseMetaData(this); this.olapDatabases = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.DISCOVER_DATASOURCES, new XmlaOlap4jConnection.Context( this, this.olap4jDatabaseMetaData, null, null, null, null, null, null), new XmlaOlap4jConnection.DatabaseHandler(), null); } /** * Returns the error-handler * @return Error-handler */ private XmlaHelper getHelper() { return helper; } /** * Initializes a cache object and configures it if cache * parameters were specified in the jdbc url. * * @param map The parameters from the jdbc url. * @throws OlapException Thrown when there is an error encountered * while creating the cache. */ private void initSoapCache(Map map) throws OlapException { // Test if a SOAP cache class was defined if (map.containsKey(XmlaOlap4jDriver.Property.CACHE.name())) { // Create a properties object to pass to the proxy // so it can configure it's cache Map props = new HashMap(); // Iterate over map entries to find those related to // the cache config for (Entry entry : map.entrySet()) { // Check if the current entry relates to cache config. if (entry.getKey().startsWith( XmlaOlap4jDriver.Property.CACHE.name() + ".")) { props.put(entry.getKey().substring( XmlaOlap4jDriver.Property.CACHE.name() .length() + 1), entry.getValue()); } } // Init the cache ((XmlaOlap4jCachedProxy) this.proxy).setCache(map, props); } } static Map parseConnectString(String url, Properties info) { String x = url.substring(CONNECT_STRING_PREFIX.length()); Map map = ConnectStringParser.parseConnectString(x); for (Map.Entry entry : toMap(info).entrySet()) { map.put(entry.getKey(), entry.getValue()); } return map; } static boolean acceptsURL(String url) { return url.startsWith(CONNECT_STRING_PREFIX); } String makeConnectionPropertyList() { StringBuilder buf = new StringBuilder(); for (String prop : databaseProperties.keySet()) { if (prop.startsWith( XmlaOlap4jDriver.Property.CACHE.name())) { // Skip over the pass-through properties for the cache. continue; } try { XmlaOlap4jDriver.Property.valueOf(prop); continue; } catch (IllegalArgumentException e) { buf.append(" <"); xmlEncode(buf, prop); buf.append(">"); xmlEncode(buf, databaseProperties.get(prop)); buf.append("\n"); } } return buf.toString(); } public OlapStatement createStatement() { return factory.newStatement(this); } public PreparedStatement prepareStatement(String sql) throws SQLException { throw new UnsupportedOperationException(); } public CallableStatement prepareCall(String sql) throws SQLException { throw new UnsupportedOperationException(); } public String nativeSQL(String sql) throws SQLException { throw new UnsupportedOperationException(); } public void setAutoCommit(boolean autoCommit) throws SQLException { this.autoCommit = autoCommit; } public boolean getAutoCommit() throws SQLException { return autoCommit; } public void commit() throws SQLException { throw new UnsupportedOperationException(); } public void rollback() throws SQLException { throw new UnsupportedOperationException(); } public void close() throws SQLException { closed = true; } public boolean isClosed() throws SQLException { return closed; } public OlapDatabaseMetaData getMetaData() { return olap4jDatabaseMetaData; } public void setReadOnly(boolean readOnly) throws SQLException { this.readOnly = readOnly; } public boolean isReadOnly() throws SQLException { return readOnly; } public void setDatabase(String databaseName) throws OlapException { if (databaseName == null) { throw new OlapException("Database name cannot be null."); } this.olap4jDatabase = (XmlaOlap4jDatabase) getOlapDatabases().get(databaseName); if (this.olap4jDatabase == null) { throw new OlapException( "No database named " + databaseName + " could be found."); } this.databaseName = databaseName; this.olap4jCatalog = null; this.olap4jSchema = null; } public String getDatabase() throws OlapException { return getOlapDatabase().getName(); } public Database getOlapDatabase() throws OlapException { if (this.olap4jDatabase == null) { if (this.databaseName == null) { List databases = getOlapDatabases(); if (databases.size() == 0) { throw new OlapException("No database found."); } this.olap4jDatabase = (XmlaOlap4jDatabase) databases.get(0); this.databaseName = this.olap4jDatabase.getName(); this.olap4jCatalog = null; this.olap4jSchema = null; } else { this.olap4jDatabase = (XmlaOlap4jDatabase) getOlapDatabases() .get(this.databaseName); this.olap4jCatalog = null; this.olap4jSchema = null; if (this.olap4jDatabase == null) { throw new OlapException( "No database named " + this.databaseName + " could be found."); } } } return olap4jDatabase; } public NamedList getOlapDatabases() throws OlapException { return Olap4jUtil.cast(this.olapDatabases); } public void setCatalog(String catalogName) throws OlapException { if (catalogName == null) { throw new OlapException("Catalog name cannot be null."); } this.olap4jCatalog = (XmlaOlap4jCatalog) getOlapCatalogs().get(catalogName); if (this.olap4jCatalog == null) { throw new OlapException( "No catalog named " + catalogName + " could be found."); } this.catalogName = catalogName; this.olap4jSchema = null; } public String getCatalog() throws OlapException { return getOlapCatalog().getName(); } public Catalog getOlapCatalog() throws OlapException { if (this.olap4jCatalog == null) { final Database database = getOlapDatabase(); if (this.catalogName == null) { if (database.getCatalogs().size() == 0) { throw new OlapException( "No catalogs could be found."); } this.olap4jCatalog = (XmlaOlap4jCatalog) database.getCatalogs().get(0); this.catalogName = this.olap4jCatalog.getName(); this.olap4jSchema = null; } else { this.olap4jCatalog = (XmlaOlap4jCatalog) database.getCatalogs() .get(this.catalogName); if (this.olap4jCatalog == null) { throw new OlapException( "No catalog named " + this.catalogName + " could be found."); } this.olap4jSchema = null; } } return olap4jCatalog; } public NamedList getOlapCatalogs() throws OlapException { return getOlapDatabase().getCatalogs(); } public String getSchema() throws OlapException { return getOlapSchema().getName(); } public void setSchema(String schemaName) throws OlapException { if (schemaName == null) { throw new OlapException("Schema name cannot be null."); } final Catalog catalog = getOlapCatalog(); this.olap4jSchema = (XmlaOlap4jSchema) catalog.getSchemas().get(schemaName); if (this.olap4jSchema == null) { throw new OlapException( "No schema named " + schemaName + " could be found in catalog " + catalog.getName()); } this.schemaName = schemaName; } public synchronized Schema getOlapSchema() throws OlapException { if (this.olap4jSchema == null) { final Catalog catalog = getOlapCatalog(); if (this.schemaName == null) { if (catalog.getSchemas().size() == 0) { throw new OlapException( "No schemas could be found."); } this.olap4jSchema = (XmlaOlap4jSchema) catalog.getSchemas().get(0); } else { this.olap4jSchema = (XmlaOlap4jSchema) catalog.getSchemas() .get(this.schemaName); if (this.olap4jSchema == null) { throw new OlapException( "No schema named " + this.schemaName + " could be found."); } } } return olap4jSchema; } public NamedList getOlapSchemas() throws OlapException { return getOlapCatalog().getSchemas(); } public void setTransactionIsolation(int level) throws SQLException { throw new UnsupportedOperationException(); } public int getTransactionIsolation() throws SQLException { return TRANSACTION_NONE; } public SQLWarning getWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void clearWarnings() throws SQLException { // this driver does not support warnings, so nothing to do } public Statement createStatement( int resultSetType, int resultSetConcurrency) throws SQLException { throw new UnsupportedOperationException(); } public PreparedStatement prepareStatement( String sql, int resultSetType, int resultSetConcurrency) throws SQLException { throw new UnsupportedOperationException(); } public CallableStatement prepareCall( String sql, int resultSetType, int resultSetConcurrency) throws SQLException { throw new UnsupportedOperationException(); } public Map> getTypeMap() throws SQLException { throw new UnsupportedOperationException(); } public void setTypeMap(Map> map) throws SQLException { throw new UnsupportedOperationException(); } public void setHoldability(int holdability) throws SQLException { throw new UnsupportedOperationException(); } public int getHoldability() throws SQLException { throw new UnsupportedOperationException(); } public Savepoint setSavepoint() throws SQLException { throw new UnsupportedOperationException(); } public Savepoint setSavepoint(String name) throws SQLException { throw new UnsupportedOperationException(); } public void rollback(Savepoint savepoint) throws SQLException { throw new UnsupportedOperationException(); } public void releaseSavepoint(Savepoint savepoint) throws SQLException { throw new UnsupportedOperationException(); } public Statement createStatement( int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } public PreparedStatement prepareStatement( String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } public CallableStatement prepareCall( String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } public PreparedStatement prepareStatement( String sql, int autoGeneratedKeys) throws SQLException { throw new UnsupportedOperationException(); } public PreparedStatement prepareStatement( String sql, int columnIndexes[]) throws SQLException { throw new UnsupportedOperationException(); } public PreparedStatement prepareStatement( String sql, String columnNames[]) throws SQLException { throw new UnsupportedOperationException(); } // implement Wrapper public T unwrap(Class iface) throws SQLException { if (iface.isInstance(this)) { return iface.cast(this); } throw getHelper().createException("does not implement '" + iface + "'"); } public boolean isWrapperFor(Class iface) throws SQLException { return iface.isInstance(this); } // implement OlapConnection public PreparedOlapStatement prepareOlapStatement( String mdx) throws OlapException { return factory.newPreparedStatement(mdx, this); } public MdxParserFactory getParserFactory() { return new MdxParserFactory() { public MdxParser createMdxParser(OlapConnection connection) { return new DefaultMdxParserImpl(); } public MdxValidator createMdxValidator(OlapConnection connection) { return new XmlaOlap4jMdxValidator(connection); } }; } public static Map toMap(final Properties properties) { return new AbstractMap() { public Set> entrySet() { return Olap4jUtil.cast(properties.entrySet()); } }; } /** * Returns the URL which was used to create this connection. * * @return URL */ String getURL() { throw Olap4jUtil.needToImplement(this); } public void setLocale(Locale locale) { if (locale == null) { throw new IllegalArgumentException("locale must not be null"); } final Locale previousLocale = this.locale; this.locale = locale; // If locale has changed, clear the cache. This is necessary because // metadata elements (e.g. Cubes) only store the caption & description // of the current locale. The SOAP cache, if enabled, will speed things // up a little if a client JVM uses connections to the same server with // different locales. if (!Olap4jUtil.equal(previousLocale, locale)) { clearCache(); } } /** * Clears the cache. */ private void clearCache() { ((DeferredNamedListImpl) this.olapDatabases).reset(); this.olap4jCatalog = null; this.olap4jDatabase = null; this.olap4jSchema = null; } public Locale getLocale() { if (locale == null) { return Locale.getDefault(); } return locale; } public void setRoleName(String roleName) throws OlapException { this.roleName = roleName; } public String getRoleName() { return roleName; } public List getAvailableRoleNames() throws OlapException { Set roleNames = new LinkedHashSet(); for (Catalog catalog : getOlapCatalogs()) { List catalogRoles = ((XmlaOlap4jCatalog) catalog).getAvailableRoles(); roleNames.addAll(catalogRoles); } return new ArrayList(roleNames); } public Scenario createScenario() { throw new UnsupportedOperationException(); } public void setScenario(Scenario scenario) { throw new UnsupportedOperationException(); } public Scenario getScenario() { throw new UnsupportedOperationException(); } void populateList( List list, Context context, MetadataRequest metadataRequest, Handler handler, Object[] restrictions) throws OlapException { String request = generateRequest(context, metadataRequest, restrictions); Element root = executeMetadataRequest(request); for (Element o : childElements(root)) { if (o.getLocalName().equals("row")) { handler.handle(o, context, list); } } handler.sortList(list); } /** * Executes an XMLA metadata request and returns the root element of the * response. * * @param request XMLA request string * @return Root element of the response * @throws OlapException on error */ Element executeMetadataRequest(String request) throws OlapException { byte[] bytes; if (DEBUG) { System.out.println("********************************************"); System.out.println("** SENDING REQUEST :"); System.out.println(request); } try { bytes = proxy.get(serverInfos, request); } catch (XmlaOlap4jProxyException e) { throw getHelper().createException( "This connection encountered an exception while executing a query.", e); } Document doc; try { doc = parse(bytes); } catch (IOException e) { throw getHelper().createException( "error discovering metadata", e); } catch (SAXException e) { throw getHelper().createException( "error discovering metadata", e); } // // // // // // // (see below) // // // // // final Element envelope = doc.getDocumentElement(); if (DEBUG) { System.out.println("** SERVER RESPONSE :"); System.out.println(XmlaOlap4jUtil.toString(doc, true)); } assert envelope.getLocalName().equals("Envelope"); assert envelope.getNamespaceURI().equals(SOAP_NS); Element body = findChild(envelope, SOAP_NS, "Body"); Element fault = findChild(body, SOAP_NS, "Fault"); if (fault != null) { /* SOAP-ENV:Client.00HSBC01 XMLA connection datasource not found Mondrian 00HSBC01 The Mondrian XML: Mondrian Error:Internal error: no catalog named 'LOCALDB' */ // TODO: log doc to logfile throw getHelper().createException( "XMLA provider gave exception: " + XmlaOlap4jUtil.prettyPrint(fault) + "\n" + "Request was:\n" + request); } Element discoverResponse = findChild(body, XMLA_NS, "DiscoverResponse"); Element returnElement = findChild(discoverResponse, XMLA_NS, "return"); return findChild(returnElement, ROWSET_NS, "root"); } /** * Generates a metadata request. * *

The list of restrictions must have even length. Even elements must * be a string (the name of the restriction); odd elements must be either * a string (the value of the restriction) or a list of strings (multiple * values of the restriction) * * @param context Context * @param metadataRequest Metadata request * @param restrictions List of restrictions * @return XMLA SOAP request as a string. * * @throws OlapException when the query depends on a datasource name but * the one specified doesn't exist at the url, or there are no default * datasource (should use the first one) */ public String generateRequest( Context context, MetadataRequest metadataRequest, Object[] restrictions) throws OlapException { final String content = "Data"; final String encoding = proxy.getEncodingCharsetName(); final StringBuilder buf = new StringBuilder( "\n" + "\n" + " \n" + " \n" + " "); buf.append(metadataRequest.name()); buf.append( "\n" + " \n" + " \n"); String restrictedCatalogName = null; if (restrictions.length > 0) { if (restrictions.length % 2 != 0) { throw new IllegalArgumentException(); } for (int i = 0; i < restrictions.length; i += 2) { final String restriction = (String) restrictions[i]; final Object o = restrictions[i + 1]; if (o instanceof String) { buf.append("<").append(restriction).append(">"); final String value = (String) o; xmlEncode(buf, value); buf.append(""); // To remind ourselves to generate a restriction // if the request supports it. if (restriction.equals("CATALOG_NAME")) { restrictedCatalogName = value; } } else { //noinspection unchecked List valueList = (List) o; for (String value : valueList) { buf.append("<").append(restriction).append(">"); xmlEncode(buf, value); buf.append(""); } } } } buf.append( " \n" + " \n" + " \n" + " \n"); String conProperties = makeConnectionPropertyList(); if (conProperties != null && !("".equals(conProperties))) { buf.append(conProperties); } if (roleName != null && !("".equals(roleName))) { buf.append(" "); xmlEncode(buf, roleName); buf.append("\n"); } // Add the datasource node only if this request requires it. if (metadataRequest.requiresDatasourceName()) { buf.append(" "); xmlEncode(buf, context.olap4jConnection.getDatabase()); buf.append("\n"); } String requestCatalogName = null; if (restrictedCatalogName != null && restrictedCatalogName.length() > 0) { requestCatalogName = restrictedCatalogName; } // If the request requires catalog name, and one wasn't specified in the // restrictions, use the connection's current catalog. if (context.olap4jCatalog != null) { requestCatalogName = context.olap4jCatalog.getName(); } if (requestCatalogName == null && metadataRequest.requiresCatalogName()) { List catalogs = context.olap4jConnection.getOlapCatalogs(); if (catalogs.size() > 0) { requestCatalogName = catalogs.get(0).getName(); } } // Add the catalog node only if this request has specified it as a // restriction. // // For low-level objects like cube, the restriction is optional; you can // specify null to not restrict, "" to match cubes whose catalog name is // empty, or a string (not interpreted as a wild card). (See // OlapDatabaseMetaData.getCubes API doc for more details.) We assume // that the request provides the restriction only if it is valid. // // For high level objects like data source and catalog, the catalog // restriction does not make sense. if (requestCatalogName != null && metadataRequest.allowsCatalogName()) { if (getOlapCatalogs() .get(requestCatalogName) == null) { throw new OlapException( "No catalog named " + requestCatalogName + " exist on the server."); } buf.append(" "); xmlEncode(buf, requestCatalogName); buf.append("\n"); } if (metadataRequest.allowsLocale()) { final Locale locale1 = context.olap4jConnection.getLocale(); if (locale1 != null) { final short lcid = LcidLocale.localeToLcid(locale1); buf.append("") .append(lcid) .append(""); } } buf.append(" "); xmlEncode(buf, content); buf.append( "\n" + " \n" + " \n" + " \n" + "\n" + ""); return buf.toString(); } /** * Encodes a string for use in an XML CDATA section. * * @param value Value to be xml encoded * @param buf Buffer to append to */ private static void xmlEncode(StringBuilder buf, String value) { final int n = value.length(); for (int i = 0; i < n; ++i) { char c = value.charAt(i); switch (c) { case '&': buf.append("&"); break; case '<': buf.append("<"); break; case '>': buf.append(">"); break; case '"': buf.append("""); break; case '\'': buf.append("'"); break; default: buf.append(c); } } } // ~ inner classes -------------------------------------------------------- static class DatabaseHandler extends HandlerImpl { public void handle( Element row, Context context, List list) { String dsName = XmlaOlap4jUtil.stringElement(row, "DataSourceName"); String dsDesc = XmlaOlap4jUtil.stringElement(row, "DataSourceDescription"); String url = XmlaOlap4jUtil.stringElement(row, "URL"); String dsInfo = XmlaOlap4jUtil.stringElement(row, "DataSourceInfo"); String providerName = XmlaOlap4jUtil.stringElement(row, "ProviderName"); StringTokenizer st = new StringTokenizer( XmlaOlap4jUtil.stringElement(row, "ProviderType"), ","); List pTypeList = new ArrayList(); while (st.hasMoreTokens()) { pTypeList.add(ProviderType.valueOf(st.nextToken())); } st = new StringTokenizer( XmlaOlap4jUtil.stringElement(row, "AuthenticationMode"), ","); List aModeList = new ArrayList(); while (st.hasMoreTokens()) { aModeList.add(AuthenticationMode.valueOf(st.nextToken())); } list.add( new XmlaOlap4jDatabase( context.olap4jConnection, dsName, dsDesc, providerName, url, dsInfo, pTypeList, aModeList)); } } static class CatalogHandler extends HandlerImpl { private final XmlaOlap4jDatabase database; public CatalogHandler(XmlaOlap4jDatabase database) { this.database = database; } public void handle( Element row, Context context, List list) { /* Example: FoodMart No description available California manager,No HR Cube */ String catalogName = XmlaOlap4jUtil.stringElement(row, "CATALOG_NAME"); String roles = XmlaOlap4jUtil.stringElement(row, "ROLES"); List roleList = new ArrayList(); if (roles != null && !"".equals(roles)) { for (String role : roles.split(",")) { roleList.add(role); } } // Unused: DESCRIPTION list.add( new XmlaOlap4jCatalog( context.olap4jDatabaseMetaData, database, catalogName, roleList)); } } static class CubeHandler extends HandlerImpl { public void handle( Element row, Context context, List list) throws OlapException { /* Example: FoodMart FoodMart HR CUBE true false false false FoodMart Schema - HR Cube */ // Unused: CATALOG_NAME, SCHEMA_NAME, CUBE_TYPE, // IS_DRILLTHROUGH_ENABLED, IS_WRITE_ENABLED, IS_LINKABLE, // IS_SQL_ENABLED String cubeName = stringElement(row, "CUBE_NAME"); String caption = stringElement(row, "CUBE_CAPTION"); if (caption == null) { caption = cubeName; } String description = stringElement(row, "DESCRIPTION"); list.add( new XmlaOlap4jCube( context.olap4jSchema, cubeName, caption, description)); } } static class DimensionHandler extends HandlerImpl { private final XmlaOlap4jCube cubeForCallback; public DimensionHandler(XmlaOlap4jCube cube) { this.cubeForCallback = cube; } public void handle( Element row, Context context, List list) { /* Example: FoodMart FoodMart HR Department [Department] Department 6 3 13 [Department] HR Cube - Department Dimension false false 0 true */ final String dimensionName = stringElement(row, "DIMENSION_NAME"); final String dimensionUniqueName = stringElement(row, "DIMENSION_UNIQUE_NAME"); final String dimensionCaption = stringElement(row, "DIMENSION_CAPTION"); final String description = stringElement(row, "DESCRIPTION"); final int dimensionType = integerElement(row, "DIMENSION_TYPE"); final Dimension.Type type = Dimension.Type.getDictionary().forOrdinal(dimensionType); final String defaultHierarchyUniqueName = stringElement(row, "DEFAULT_HIERARCHY"); final Integer dimensionOrdinal = integerElement(row, "DIMENSION_ORDINAL"); XmlaOlap4jDimension dimension = new XmlaOlap4jDimension( context.olap4jCube, dimensionUniqueName, dimensionName, dimensionCaption, description, type, defaultHierarchyUniqueName, dimensionOrdinal == null ? 0 : dimensionOrdinal); list.add(dimension); if (dimensionOrdinal != null) { Collections.sort( list, new Comparator () { public int compare( XmlaOlap4jDimension d1, XmlaOlap4jDimension d2) { if (d1.getOrdinal() == d2.getOrdinal()) { return 0; } else if (d1.getOrdinal() > d2.getOrdinal()) { return 1; } else { return -1; } } }); } this.cubeForCallback.dimensionsByUname.put( dimension.getUniqueName(), dimension); } } static class HierarchyHandler extends HandlerImpl { private final XmlaOlap4jCube cubeForCallback; public HierarchyHandler(XmlaOlap4jCube cubeForCallback) { this.cubeForCallback = cubeForCallback; } public void handle( Element row, Context context, List list) throws OlapException { /* Example: FoodMart FoodMart Sales [Customers] Customers [Customers] Customers 3 10407 [Customers].[All Customers] [Customers].[All Customers] Sales Cube - Customers Hierarchy 0 false false 0 true 9 true false */ 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 != null ? hierarchyUniqueName.replaceAll("^\\[", "") .replaceAll("\\]$", "") : null) : stringElement(row, "HIERARCHY_NAME"); final String hierarchyCaption = stringElement(row, "HIERARCHY_CAPTION"); final String description = stringElement(row, "DESCRIPTION"); final String allMember = stringElement(row, "ALL_MEMBER"); final String defaultMemberUniqueName = stringElement(row, "DEFAULT_MEMBER"); XmlaOlap4jHierarchy hierarchy = new XmlaOlap4jHierarchy( context.getDimension(row), hierarchyUniqueName, hierarchyName, hierarchyCaption, description, allMember != null, defaultMemberUniqueName); list.add(hierarchy); cubeForCallback.hierarchiesByUname.put( hierarchy.getUniqueName(), hierarchy); } } static class LevelHandler extends HandlerImpl { public static final int MDLEVEL_TYPE_CALCULATED = 0x0002; private final XmlaOlap4jCube cubeForCallback; public LevelHandler(XmlaOlap4jCube cubeForCallback) { this.cubeForCallback = cubeForCallback; } public void handle( Element row, Context context, List list) { /* Example: FoodMart FoodMart Sales [Customers] [Customers] (All) [Customers].[(All)] (All) 0 1 1 0 3 true Sales Cube - Customers Hierarchy - (All) Level */ 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 != null ? levelUniqueName.replaceAll("^\\[", "") .replaceAll("\\]$", "") : null) : stringElement(row, "LEVEL_NAME"); final String levelCaption = stringElement(row, "LEVEL_CAPTION"); final String description = stringElement(row, "DESCRIPTION"); final int levelNumber = integerElement(row, "LEVEL_NUMBER"); final Integer levelTypeCode = integerElement(row, "LEVEL_TYPE"); final Level.Type levelType = Level.Type.getDictionary().forOrdinal(levelTypeCode); boolean calculated = (levelTypeCode & MDLEVEL_TYPE_CALCULATED) != 0; final int levelCardinality = integerElement(row, "LEVEL_CARDINALITY"); XmlaOlap4jLevel level = new XmlaOlap4jLevel( context.getHierarchy(row), levelUniqueName, levelName, levelCaption, description, levelNumber, levelType, calculated, levelCardinality); list.add(level); cubeForCallback.levelsByUname.put( level.getUniqueName(), level); } } static class MeasureHandler extends HandlerImpl { public void handle( Element row, Context context, List list) throws OlapException { /* Example: FoodMart FoodMart Sales Profit [Measures].[Profit] Profit 127 130 true Sales Cube - Profit Member */ final String measureName = stringElement(row, "MEASURE_NAME"); final String measureUniqueName = stringElement(row, "MEASURE_UNIQUE_NAME"); final String measureCaption = stringElement(row, "MEASURE_CAPTION"); final String description = stringElement(row, "DESCRIPTION"); final Measure.Aggregator measureAggregator = Measure.Aggregator.getDictionary().forOrdinal( integerElement( row, "MEASURE_AGGREGATOR")); 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"); final Member member = context.getCube(row).getMetadataReader() .lookupMemberByUniqueName( measureUniqueName); 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( (XmlaOlap4jLevel)member.getLevel(), measureUniqueName, measureName, measureCaption, description, null, measureAggregator, datatype, measureIsVisible, member.getOrdinal())); } public void sortList(List list) { Collections.sort( list, new Comparator() { public int compare( XmlaOlap4jMeasure o1, XmlaOlap4jMeasure o2) { return o1.getOrdinal() - o2.getOrdinal(); } } ); } } static class MemberHandler extends HandlerImpl { /** * Collection of nodes to ignore because they represent standard * built-in properties of Members. */ private static final Set EXCLUDED_PROPERTY_NAMES = new HashSet( Arrays.asList( Property.StandardMemberProperty.CATALOG_NAME.name(), Property.StandardMemberProperty.CUBE_NAME.name(), Property.StandardMemberProperty.DIMENSION_UNIQUE_NAME .name(), Property.StandardMemberProperty.HIERARCHY_UNIQUE_NAME .name(), Property.StandardMemberProperty.LEVEL_UNIQUE_NAME.name(), Property.StandardMemberProperty.PARENT_LEVEL.name(), Property.StandardMemberProperty.PARENT_COUNT.name(), Property.StandardMemberProperty.MEMBER_KEY.name(), Property.StandardMemberProperty.IS_PLACEHOLDERMEMBER.name(), Property.StandardMemberProperty.IS_DATAMEMBER.name(), Property.StandardMemberProperty.LEVEL_NUMBER.name(), Property.StandardMemberProperty.MEMBER_ORDINAL.name(), Property.StandardMemberProperty.MEMBER_UNIQUE_NAME.name(), Property.StandardMemberProperty.MEMBER_NAME.name(), Property.StandardMemberProperty.PARENT_UNIQUE_NAME.name(), Property.StandardMemberProperty.MEMBER_TYPE.name(), Property.StandardMemberProperty.MEMBER_CAPTION.name(), Property.StandardMemberProperty.CHILDREN_CARDINALITY.name(), Property.StandardMemberProperty.DEPTH.name())); /** * Cached value returned by the {@link Member.Type#values} method, which * calls {@link Class#getEnumConstants()} and unfortunately clones an * array every time. */ private static final Member.Type[] MEMBER_TYPE_VALUES = Member.Type.values(); public void handle( Element row, Context context, List list) { /* Example: FoodMart FoodMart Sales [Gender] [Gender] [Gender].[Gender] 1 1 F [Gender].[F] 1 F 0 0 [Gender].[All Gender] 1 1 */ if (false) { int levelNumber = integerElement( row, Property.StandardMemberProperty.LEVEL_NUMBER.name()); } int memberOrdinal = integerElement( row, Property.StandardMemberProperty.MEMBER_ORDINAL.name()); String memberUniqueName = stringElement( row, Property.StandardMemberProperty.MEMBER_UNIQUE_NAME.name()); String memberName = stringElement( row, Property.StandardMemberProperty.MEMBER_NAME.name()); String parentUniqueName = stringElement( row, Property.StandardMemberProperty.PARENT_UNIQUE_NAME.name()); Member.Type memberType = MEMBER_TYPE_VALUES[ integerElement( row, Property.StandardMemberProperty.MEMBER_TYPE.name())]; String memberCaption = stringElement( row, Property.StandardMemberProperty.MEMBER_CAPTION.name()); int childrenCardinality = integerElement( row, Property.StandardMemberProperty.CHILDREN_CARDINALITY .name()); // Gather member property values into a temporary map, so we can // create the member with all properties known. XmlaOlap4jMember // uses an ArrayMap for property values and it is not efficient to // add entries to the map one at a time. final XmlaOlap4jLevel level = context.getLevel(row); final Map map = new HashMap(); addUserDefinedDimensionProperties(row, level, map); // Usually members have the same depth as their level. (Ragged and // parent-child hierarchies are an exception.) Only store depth for // the unusual ones. final Integer depth = integerElement( row, Property.StandardMemberProperty.DEPTH.name()); if (depth != null && depth.intValue() != level.getDepth()) { map.put( Property.StandardMemberProperty.DEPTH, depth); } // 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. XmlaOlap4jMember member = new XmlaOlap4jMember( level, memberUniqueName, memberName, memberCaption, "", parentUniqueName, memberType, childrenCardinality, memberOrdinal, map); list.add(member); } private void addUserDefinedDimensionProperties( Element row, XmlaOlap4jLevel level, Map map) { NodeList nodes = row.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (EXCLUDED_PROPERTY_NAMES.contains(node.getLocalName())) { continue; } for (Property property : level.getProperties()) { if (property instanceof XmlaOlap4jProperty && property.getName().equalsIgnoreCase( node.getLocalName())) { map.put(property, node.getTextContent()); } } } } } static class NamedSetHandler extends HandlerImpl { public void handle( Element row, Context context, List list) { /* Example: FoodMart FoodMart Warehouse [Top Sellers] 1 */ final String setName = stringElement(row, "SET_NAME"); list.add( new XmlaOlap4jNamedSet( context.getCube(row), setName)); } } static class SchemaHandler extends HandlerImpl { public void handle( Element row, Context context, List list) throws OlapException { /* Example: LOCALDB FoodMart dbo */ String schemaName = stringElement(row, "SCHEMA_NAME"); list.add( new XmlaOlap4jSchema( context.getCatalog(row), (schemaName == null) ? "" : schemaName)); } } static class CatalogSchemaHandler extends HandlerImpl { private String catalogName; public CatalogSchemaHandler(String catalogName) { super(); if (catalogName == null) { throw new RuntimeException( "The CatalogSchemaHandler handler requires a catalog " + "name."); } this.catalogName = catalogName; } public void handle( Element row, Context context, List list) throws OlapException { /* Example: CatalogName FoodMart dbo */ // We are looking for a schema name from the cubes query restricted // on the catalog name. Some servers don't support nor include the // SCHEMA_NAME column in its response. If it's null, we convert it // to an empty string as to not cause problems later on. final String schemaName = stringElement(row, "SCHEMA_NAME"); final String catalogName = stringElement(row, "CATALOG_NAME"); final String schemaName2 = (schemaName == null) ? "" : schemaName; if (this.catalogName.equals(catalogName) && ((NamedList)list).get(schemaName2) == null) { list.add( new XmlaOlap4jSchema( context.getCatalog(row), schemaName2)); } } } static class PropertyHandler extends HandlerImpl { public void handle( Element row, Context context, List list) throws OlapException { /* Example: FoodMart FoodMart HR [Store] [Store] [Store].[Store Name] Store Manager Store Manager 1 130 0 HR Cube - Store Hierarchy - Store Name Level - Store Manager Property */ String description = stringElement(row, "DESCRIPTION"); String uniqueName = stringElement(row, "DESCRIPTION"); String caption = stringElement(row, "PROPERTY_CAPTION"); String name = stringElement(row, "PROPERTY_NAME"); 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 = contentTypeOrdinal == null ? null : Property.ContentType.getDictionary().forOrdinal( contentTypeOrdinal); int propertyType = integerElement(row, "PROPERTY_TYPE"); Set type = Property.TypeFlag.getDictionary().forMask(propertyType); list.add( new XmlaOlap4jProperty( uniqueName, name, caption, description, datatype, type, contentType)); } } /** * Callback for converting XMLA results into metadata elements. */ interface Handler { /** * Converts an XML element from an XMLA result set into a metadata * element and appends it to a list of metadata elements. * * @param row XMLA element * * @param context Context (schema, cube, dimension, etc.) that the * request was executed in and that the element will belong to * * @param list List of metadata elements to append new metadata element * * @throws OlapException on error */ void handle( Element row, Context context, List list) throws OlapException; /** * Sorts a list of metadata elements. * *

For most element types, the order returned by XMLA is correct, and * this method will no-op. * * @param list List of metadata elements */ void sortList(List list); } static abstract class HandlerImpl implements Handler { public void sortList(List list) { // do nothing - assume XMLA returned list in correct order } } static class Context { final XmlaOlap4jConnection olap4jConnection; final XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData; final XmlaOlap4jCatalog olap4jCatalog; final XmlaOlap4jSchema olap4jSchema; final XmlaOlap4jCube olap4jCube; final XmlaOlap4jDimension olap4jDimension; final XmlaOlap4jHierarchy olap4jHierarchy; final XmlaOlap4jLevel olap4jLevel; /** * Creates a Context. * * @param olap4jConnection Connection (must not be null) * @param olap4jDatabaseMetaData DatabaseMetaData (may be null) * @param olap4jCatalog Catalog (may be null if DatabaseMetaData is * null) * @param olap4jSchema Schema (may be null if Catalog is null) * @param olap4jCube Cube (may be null if Schema is null) * @param olap4jDimension Dimension (may be null if Cube is null) * @param olap4jHierarchy Hierarchy (may be null if Dimension is null) * @param olap4jLevel Level (may be null if Hierarchy is null) */ Context( XmlaOlap4jConnection olap4jConnection, XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData, XmlaOlap4jCatalog olap4jCatalog, XmlaOlap4jSchema olap4jSchema, XmlaOlap4jCube olap4jCube, XmlaOlap4jDimension olap4jDimension, XmlaOlap4jHierarchy olap4jHierarchy, XmlaOlap4jLevel olap4jLevel) { this.olap4jConnection = olap4jConnection; this.olap4jDatabaseMetaData = olap4jDatabaseMetaData; this.olap4jCatalog = olap4jCatalog; this.olap4jSchema = olap4jSchema; this.olap4jCube = olap4jCube; this.olap4jDimension = olap4jDimension; this.olap4jHierarchy = olap4jHierarchy; this.olap4jLevel = olap4jLevel; assert (olap4jDatabaseMetaData != null || olap4jCatalog == null) && (olap4jCatalog != null || olap4jSchema == null) && (olap4jSchema != null || olap4jCube == null) && (olap4jCube != null || olap4jDimension == null) && (olap4jDimension != null || olap4jHierarchy == null) && (olap4jHierarchy != null || olap4jLevel == null); } /** * Shorthand way to create a Context at Cube level or finer. * * @param olap4jCube Cube (must not be null) * @param olap4jDimension Dimension (may be null) * @param olap4jHierarchy Hierarchy (may be null if Dimension is null) * @param olap4jLevel Level (may be null if Hierarchy is null) */ Context( XmlaOlap4jCube olap4jCube, XmlaOlap4jDimension olap4jDimension, XmlaOlap4jHierarchy olap4jHierarchy, XmlaOlap4jLevel olap4jLevel) { this( olap4jCube.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection, olap4jCube.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData, olap4jCube.olap4jSchema.olap4jCatalog, olap4jCube.olap4jSchema, olap4jCube, olap4jDimension, olap4jHierarchy, olap4jLevel); } /** * Shorthand way to create a Context at Level level. * * @param olap4jLevel Level (must not be null) */ Context(XmlaOlap4jLevel olap4jLevel) { this( olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube, olap4jLevel.olap4jHierarchy.olap4jDimension, olap4jLevel.olap4jHierarchy, olap4jLevel); } XmlaOlap4jHierarchy getHierarchy(Element row) { if (olap4jHierarchy != null) { return olap4jHierarchy; } final String hierarchyUniqueName = stringElement(row, "HIERARCHY_UNIQUE_NAME"); XmlaOlap4jHierarchy hierarchy = getCube(row).hierarchiesByUname.get(hierarchyUniqueName); if (hierarchy == null) { // Apparently, the code has requested a member that is // not queried for yet. We must force the initialization // of the dimension tree first. final String dimensionUniqueName = stringElement(row, "DIMENSION_UNIQUE_NAME"); String dimensionName = Olap4jUtil.parseUniqueName(dimensionUniqueName).get(0); XmlaOlap4jDimension dimension = getCube(row).dimensions.get(dimensionName); dimension.getHierarchies().size(); // Now we attempt to resolve again hierarchy = getCube(row).hierarchiesByUname.get(hierarchyUniqueName); } return hierarchy; } XmlaOlap4jCube getCube(Element row) { if (olap4jCube != null) { return olap4jCube; } throw new UnsupportedOperationException(); // todo: } XmlaOlap4jDimension getDimension(Element row) { if (olap4jDimension != null) { return olap4jDimension; } final String dimensionUniqueName = stringElement(row, "DIMENSION_UNIQUE_NAME"); XmlaOlap4jDimension dimension = getCube(row) .dimensionsByUname.get(dimensionUniqueName); // Apparently, the code has requested a member that is // not queried for yet. if (dimension == null) { final String dimensionName = stringElement(row, "DIMENSION_NAME"); return getCube(row).dimensions.get(dimensionName); } return dimension; } public XmlaOlap4jLevel getLevel(Element row) { if (olap4jLevel != null) { return olap4jLevel; } final String levelUniqueName = stringElement(row, "LEVEL_UNIQUE_NAME"); XmlaOlap4jLevel level = getCube(row).levelsByUname.get(levelUniqueName); if (level == null) { // Apparently, the code has requested a member that is // not queried for yet. We must force the initialization // of the dimension tree first. final String dimensionUniqueName = stringElement(row, "DIMENSION_UNIQUE_NAME"); String dimensionName = Olap4jUtil.parseUniqueName(dimensionUniqueName).get(0); XmlaOlap4jDimension dimension = getCube(row).dimensions.get(dimensionName); for (Hierarchy hierarchyInit : dimension.getHierarchies()) { hierarchyInit.getLevels().size(); } // Now we attempt to resolve again level = getCube(row).levelsByUname.get(levelUniqueName); } return level; } public XmlaOlap4jCatalog getCatalog(Element row) throws OlapException { if (olap4jCatalog != null) { return olap4jCatalog; } final String catalogName = stringElement(row, "CATALOG_NAME"); return (XmlaOlap4jCatalog) olap4jConnection.getOlapCatalogs().get( catalogName); } } enum MetadataRequest { DISCOVER_DATASOURCES( new MetadataColumn("DataSourceName"), new MetadataColumn("DataSourceDescription"), new MetadataColumn("URL"), new MetadataColumn("DataSourceInfo"), new MetadataColumn("ProviderName"), new MetadataColumn("ProviderType"), new MetadataColumn("AuthenticationMode")), DISCOVER_SCHEMA_ROWSETS( new MetadataColumn("SchemaName"), new MetadataColumn("SchemaGuid"), new MetadataColumn("Restrictions"), new MetadataColumn("Description")), DISCOVER_ENUMERATORS( new MetadataColumn("EnumName"), new MetadataColumn("EnumDescription"), new MetadataColumn("EnumType"), new MetadataColumn("ElementName"), new MetadataColumn("ElementDescription"), new MetadataColumn("ElementValue")), DISCOVER_PROPERTIES( new MetadataColumn("PropertyName"), new MetadataColumn("PropertyDescription"), new MetadataColumn("PropertyType"), new MetadataColumn("PropertyAccessType"), new MetadataColumn("IsRequired"), new MetadataColumn("Value")), DISCOVER_KEYWORDS( new MetadataColumn("Keyword")), DISCOVER_LITERALS( new MetadataColumn("LiteralName"), new MetadataColumn("LiteralValue"), new MetadataColumn("LiteralInvalidChars"), new MetadataColumn("LiteralInvalidStartingChars"), new MetadataColumn("LiteralMaxLength")), DBSCHEMA_CATALOGS( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("DESCRIPTION"), new MetadataColumn("ROLES"), new MetadataColumn("DATE_MODIFIED")), DBSCHEMA_COLUMNS( new MetadataColumn("TABLE_CATALOG"), new MetadataColumn("TABLE_SCHEMA"), new MetadataColumn("TABLE_NAME"), new MetadataColumn("COLUMN_NAME"), new MetadataColumn("ORDINAL_POSITION"), new MetadataColumn("COLUMN_HAS_DEFAULT"), new MetadataColumn("COLUMN_FLAGS"), new MetadataColumn("IS_NULLABLE"), new MetadataColumn("DATA_TYPE"), new MetadataColumn("CHARACTER_MAXIMUM_LENGTH"), new MetadataColumn("CHARACTER_OCTET_LENGTH"), new MetadataColumn("NUMERIC_PRECISION"), new MetadataColumn("NUMERIC_SCALE")), DBSCHEMA_PROVIDER_TYPES( new MetadataColumn("TYPE_NAME"), new MetadataColumn("DATA_TYPE"), new MetadataColumn("COLUMN_SIZE"), new MetadataColumn("LITERAL_PREFIX"), new MetadataColumn("LITERAL_SUFFIX"), new MetadataColumn("IS_NULLABLE"), new MetadataColumn("CASE_SENSITIVE"), new MetadataColumn("SEARCHABLE"), new MetadataColumn("UNSIGNED_ATTRIBUTE"), new MetadataColumn("FIXED_PREC_SCALE"), new MetadataColumn("AUTO_UNIQUE_VALUE"), new MetadataColumn("IS_LONG"), new MetadataColumn("BEST_MATCH")), DBSCHEMA_TABLES( new MetadataColumn("TABLE_CATALOG"), new MetadataColumn("TABLE_SCHEMA"), new MetadataColumn("TABLE_NAME"), new MetadataColumn("TABLE_TYPE"), new MetadataColumn("TABLE_GUID"), new MetadataColumn("DESCRIPTION"), new MetadataColumn("TABLE_PROPID"), new MetadataColumn("DATE_CREATED"), new MetadataColumn("DATE_MODIFIED")), DBSCHEMA_TABLES_INFO( new MetadataColumn("TABLE_CATALOG"), new MetadataColumn("TABLE_SCHEMA"), new MetadataColumn("TABLE_NAME"), new MetadataColumn("TABLE_TYPE"), new MetadataColumn("TABLE_GUID"), new MetadataColumn("BOOKMARKS"), new MetadataColumn("BOOKMARK_TYPE"), new MetadataColumn("BOOKMARK_DATATYPE"), new MetadataColumn("BOOKMARK_MAXIMUM_LENGTH"), new MetadataColumn("BOOKMARK_INFORMATION"), new MetadataColumn("TABLE_VERSION"), new MetadataColumn("CARDINALITY"), new MetadataColumn("DESCRIPTION"), new MetadataColumn("TABLE_PROPID")), DBSCHEMA_SCHEMATA( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("SCHEMA_OWNER")), MDSCHEMA_ACTIONS( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("ACTION_NAME"), new MetadataColumn("COORDINATE"), new MetadataColumn("COORDINATE_TYPE")), MDSCHEMA_CUBES( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("CUBE_TYPE"), new MetadataColumn("CUBE_GUID"), new MetadataColumn("CREATED_ON"), new MetadataColumn("LAST_SCHEMA_UPDATE"), new MetadataColumn("SCHEMA_UPDATED_BY"), new MetadataColumn("LAST_DATA_UPDATE"), new MetadataColumn("DATA_UPDATED_BY"), new MetadataColumn("IS_DRILLTHROUGH_ENABLED"), new MetadataColumn("IS_WRITE_ENABLED"), new MetadataColumn("IS_LINKABLE"), new MetadataColumn("IS_SQL_ENABLED"), new MetadataColumn("DESCRIPTION"), new MetadataColumn("CUBE_CAPTION"), new MetadataColumn("BASE_CUBE_NAME")), MDSCHEMA_DIMENSIONS( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("DIMENSION_NAME"), new MetadataColumn("DIMENSION_UNIQUE_NAME"), new MetadataColumn("DIMENSION_GUID"), new MetadataColumn("DIMENSION_CAPTION"), new MetadataColumn("DIMENSION_ORDINAL"), new MetadataColumn("DIMENSION_TYPE"), new MetadataColumn("DIMENSION_CARDINALITY"), new MetadataColumn("DEFAULT_HIERARCHY"), new MetadataColumn("DESCRIPTION"), new MetadataColumn("IS_VIRTUAL"), new MetadataColumn("IS_READWRITE"), new MetadataColumn("DIMENSION_UNIQUE_SETTINGS"), new MetadataColumn("DIMENSION_MASTER_UNIQUE_NAME"), new MetadataColumn("DIMENSION_IS_VISIBLE")), MDSCHEMA_FUNCTIONS( new MetadataColumn("FUNCTION_NAME"), new MetadataColumn("DESCRIPTION"), new MetadataColumn("PARAMETER_LIST"), new MetadataColumn("RETURN_TYPE"), new MetadataColumn("ORIGIN"), new MetadataColumn("INTERFACE_NAME"), new MetadataColumn("LIBRARY_NAME"), new MetadataColumn("CAPTION")), MDSCHEMA_HIERARCHIES( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("DIMENSION_UNIQUE_NAME"), new MetadataColumn("HIERARCHY_NAME"), new MetadataColumn("HIERARCHY_UNIQUE_NAME"), new MetadataColumn("HIERARCHY_GUID"), new MetadataColumn("HIERARCHY_CAPTION"), new MetadataColumn("DIMENSION_TYPE"), new MetadataColumn("HIERARCHY_CARDINALITY"), new MetadataColumn("DEFAULT_MEMBER"), new MetadataColumn("ALL_MEMBER"), new MetadataColumn("DESCRIPTION"), new MetadataColumn("STRUCTURE"), new MetadataColumn("IS_VIRTUAL"), new MetadataColumn("IS_READWRITE"), new MetadataColumn("DIMENSION_UNIQUE_SETTINGS"), new MetadataColumn("DIMENSION_IS_VISIBLE"), new MetadataColumn("HIERARCHY_IS_VISIBLE"), new MetadataColumn("HIERARCHY_ORDINAL"), new MetadataColumn("DIMENSION_IS_SHARED"), new MetadataColumn("PARENT_CHILD")), MDSCHEMA_LEVELS( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("DIMENSION_UNIQUE_NAME"), new MetadataColumn("HIERARCHY_UNIQUE_NAME"), new MetadataColumn("LEVEL_NAME"), new MetadataColumn("LEVEL_UNIQUE_NAME"), new MetadataColumn("LEVEL_GUID"), new MetadataColumn("LEVEL_CAPTION"), new MetadataColumn("LEVEL_NUMBER"), new MetadataColumn("LEVEL_CARDINALITY"), new MetadataColumn("LEVEL_TYPE"), new MetadataColumn("CUSTOM_ROLLUP_SETTINGS"), new MetadataColumn("LEVEL_UNIQUE_SETTINGS"), new MetadataColumn("LEVEL_IS_VISIBLE"), new MetadataColumn("DESCRIPTION")), MDSCHEMA_MEASURES( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("MEASURE_NAME"), new MetadataColumn("MEASURE_UNIQUE_NAME"), new MetadataColumn("MEASURE_CAPTION"), new MetadataColumn("MEASURE_GUID"), new MetadataColumn("MEASURE_AGGREGATOR"), new MetadataColumn("DATA_TYPE"), new MetadataColumn("MEASURE_IS_VISIBLE"), new MetadataColumn("LEVELS_LIST"), new MetadataColumn("DESCRIPTION")), MDSCHEMA_MEMBERS( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("DIMENSION_UNIQUE_NAME"), new MetadataColumn("HIERARCHY_UNIQUE_NAME"), new MetadataColumn("LEVEL_UNIQUE_NAME"), new MetadataColumn("LEVEL_NUMBER"), new MetadataColumn("MEMBER_ORDINAL"), new MetadataColumn("MEMBER_NAME"), new MetadataColumn("MEMBER_UNIQUE_NAME"), new MetadataColumn("MEMBER_TYPE"), new MetadataColumn("MEMBER_GUID"), new MetadataColumn("MEMBER_CAPTION"), new MetadataColumn("CHILDREN_CARDINALITY"), new MetadataColumn("PARENT_LEVEL"), new MetadataColumn("PARENT_UNIQUE_NAME"), new MetadataColumn("PARENT_COUNT"), new MetadataColumn("TREE_OP"), new MetadataColumn("DEPTH")), MDSCHEMA_PROPERTIES( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("DIMENSION_UNIQUE_NAME"), new MetadataColumn("HIERARCHY_UNIQUE_NAME"), new MetadataColumn("LEVEL_UNIQUE_NAME"), new MetadataColumn("MEMBER_UNIQUE_NAME"), new MetadataColumn("PROPERTY_NAME"), new MetadataColumn("PROPERTY_CAPTION"), new MetadataColumn("PROPERTY_TYPE"), new MetadataColumn("DATA_TYPE"), new MetadataColumn("PROPERTY_CONTENT_TYPE"), new MetadataColumn("DESCRIPTION")), MDSCHEMA_SETS( new MetadataColumn("CATALOG_NAME"), new MetadataColumn("SCHEMA_NAME"), new MetadataColumn("CUBE_NAME"), new MetadataColumn("SET_NAME"), new MetadataColumn("SCOPE")); final List columns; final Map columnsByName; /** * Creates a MetadataRequest. * * @param columns Columns */ MetadataRequest(MetadataColumn... columns) { if (name().equals("DBSCHEMA_CATALOGS")) { // DatabaseMetaData.getCatalogs() is defined by JDBC not XMLA, // so has just one column. Ignore the 4 columns from XMLA. columns = new MetadataColumn[] { new MetadataColumn("CATALOG_NAME", "TABLE_CAT") }; } else if (name().equals("DBSCHEMA_SCHEMATA")) { // DatabaseMetaData.getCatalogs() is defined by JDBC not XMLA, // so has just one column. Ignore the 4 columns from XMLA. columns = new MetadataColumn[] { new MetadataColumn("SCHEMA_NAME", "TABLE_SCHEM"), new MetadataColumn("CATALOG_NAME", "TABLE_CAT") }; } this.columns = UnmodifiableArrayList.asCopyOf(columns); final Map map = new HashMap(); for (MetadataColumn column : columns) { map.put(column.name, column); } this.columnsByName = Collections.unmodifiableMap(map); } /** * Returns whether this request requires a * {@code <DatasourceName>} element. * * @return whether this request requires a DatasourceName element */ public boolean requiresDatasourceName() { return this != DISCOVER_DATASOURCES; } /** * Returns whether this request requires a * {@code <CatalogName>} element. * * @return whether this request requires a CatalogName element */ public boolean requiresCatalogName() { // If we don't specifiy CatalogName in the properties of an // MDSCHEMA_FUNCTIONS request, Mondrian's XMLA provider will give // us the whole set of functions multiplied by the number of // catalogs. JDBC (and Mondrian) assumes that functions belong to a // catalog whereas XMLA (and SSAS) assume that functions belong to // the database. Always specifying a catalog is the easiest way to // reconcile them. return this == MDSCHEMA_FUNCTIONS; } /** * Returns whether this request allows a * {@code <CatalogName>} element in the properties section of the * request. Even for requests that allow it, it is usually optional. * * @return whether this request allows a CatalogName element */ public boolean allowsCatalogName() { return true; } /** * Returns the column with a given name, or null if there is no such * column. * * @param name Column name * @return Column, or null if not found */ public MetadataColumn getColumn(String name) { return columnsByName.get(name); } public boolean allowsLocale() { return name().startsWith("MDSCHEMA"); } } private static final Pattern LOWERCASE_PATTERN = Pattern.compile(".*[a-z].*"); static class MetadataColumn { final String name; final String xmlaName; MetadataColumn(String xmlaName, String name) { this.xmlaName = xmlaName; this.name = name; } MetadataColumn(String xmlaName) { this.xmlaName = xmlaName; String name = xmlaName; if (LOWERCASE_PATTERN.matcher(name).matches()) { name = Olap4jUtil.camelToUpper(name); } // VALUE is a SQL reserved word if (name.equals("VALUE")) { name = "PROPERTY_VALUE"; } this.name = name; } } private static class XmlaOlap4jMdxValidator implements MdxValidator { private final OlapConnection connection; XmlaOlap4jMdxValidator(OlapConnection connection) { this.connection = connection; } public SelectNode validateSelect( SelectNode selectNode) throws OlapException { StringWriter sw = new StringWriter(); selectNode.unparse(new ParseTreeWriter(sw)); String mdx = sw.toString(); final XmlaOlap4jConnection olap4jConnection = (XmlaOlap4jConnection) connection; return selectNode; } } } // End XmlaOlap4jConnection.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java0000644000175000017500000003440211713757446024120 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jDriver.java 490 2012-01-23 22:35:25Z lucboudreau $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.driver.xmla.proxy.XmlaOlap4jHttpProxy; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import org.olap4j.impl.Olap4jUtil; import java.sql.*; import java.util.*; import java.util.concurrent.*; import java.util.logging.Logger; /** * Olap4j driver for generic XML for Analysis (XMLA) providers. * *

Since olap4j is a superset of JDBC, you register this driver as you would * any JDBC driver: * *

* Class.forName("org.olap4j.driver.xmla.XmlaOlap4jDriver"); *
* * Then create a connection using a URL with the prefix "jdbc:xmla:". * For example, * *
* import java.sql.Connection;
* import java.sql.DriverManager;
* import org.olap4j.OlapConnection;
*
* Connection connection =
*    DriverManager.getConnection(
*       "jdbc:xmla:");
* OlapConnection olapConnection =
*    connection.unwrap(OlapConnection.class);
*
* *

Note how we use the java.sql.Connection#unwrap(Class) method to down-cast * the JDBC connection object to the extension {@link org.olap4j.OlapConnection} * object. This method is only available in JDBC 4.0 (JDK 1.6 onwards). * *

Connection properties

* *

Unless otherwise stated, properties are optional. If a property occurs * multiple times in the connect string, the first occurrence is used. * *

It is also possible to pass properties to the server end-point using * JDBC connection properties as part of the XMLA driver connection properties. * If the JDBC URL contains properties that are not enumerated in * {@link Property}, they will be included as part of the SOAP PropertyList * element. * * * * * * * * * * * * * * * * * * * *
Property Description
Server URL of HTTP server. Required.
Catalog Catalog name to use. * By default, the first one returned by the * XMLA server will be used.
Schema Schema name to use. * By default, the first one returned by the * XMLA server will be used.
Database Name of the XMLA database. * By default, the first one returned by the * XMLA server will be used.
Cache

Class name of the SOAP cache to use. * Must implement interface * {@link org.olap4j.driver.xmla.proxy.XmlaOlap4jCachedProxy}. * A built-in memory cache is available with * {@link org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache}. * *

By default, no SOAP query cache will be * used. *

Cache.* Properties to transfer to the selected cache * implementation. See * {@link org.olap4j.driver.xmla.cache.XmlaOlap4jCache} * or your selected implementation for properties * details. *
TestProxyCookieString that uniquely identifies a proxy * object in {@link #PROXY_MAP} via which to * send XMLA requests for testing * purposes. *
Role Comma separated list of role names used for * this connection (Optional).
* Available role names can be retrieved via * {@link org.olap4j.driver.xmla.XmlaOlap4jConnection#getAvailableRoleNames} *
User User name to use when establishing a * connection to the server. The credentials are * passed using the HTTP Basic authentication * protocol, but are also sent as part of the SOAP * Security headers. *
Password Password to use when establishing a * connection to the server. The credentials are * passed using the HTTP Basic authentication * protocol, but are also sent as part of the SOAP * Security headers. *
* * @author jhyde, Luc Boudreau * @version $Id: XmlaOlap4jDriver.java 490 2012-01-23 22:35:25Z lucboudreau $ * @since May 22, 2007 */ public class XmlaOlap4jDriver implements Driver { private final Factory factory; /** * Executor shared by all connections making asynchronous XMLA calls. */ private static final ExecutorService executor; static { executor = Executors.newCachedThreadPool( new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = Executors.defaultThreadFactory().newThread(r); t.setDaemon(true); return t; } } ); } private static int nextCookie; static { try { register(); } catch (SQLException e) { e.printStackTrace(); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } /** * Creates an XmlaOlap4jDriver. */ public XmlaOlap4jDriver() { factory = createFactory(); } private static Factory createFactory() { final String factoryClassName = getFactoryClassName(); try { final Class clazz = Class.forName(factoryClassName); return (Factory) clazz.newInstance(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } } /* String factoryClassName; try { Class.forName("java.sql.Wrapper"); factoryClassName = "org.olap4j.driver.xmla.FactoryJdbc4Impl"; } catch (ClassNotFoundException e) { // java.sql.Wrapper is not present. This means we are running JDBC // 3.0 or earlier (probably JDK 1.5). Load the JDBC 3.0 factory factoryClassName = "org.olap4j.driver.xmla.FactoryJdbc3Impl"; } try { final Class clazz = Class.forName(factoryClassName); factory = (Factory) clazz.newInstance(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } */ private static String getFactoryClassName() { try { // If java.sql.PseudoColumnUsage is present, we are running JDBC 4.1 // or later. Class.forName("java.sql.PseudoColumnUsage"); return "org.olap4j.driver.xmla.FactoryJdbc41Impl"; } catch (ClassNotFoundException e) { // java.sql.PseudoColumnUsage is not present. This means we are // running JDBC 4.0 or earlier. try { Class.forName("java.sql.Wrapper"); return "org.olap4j.driver.xmla.FactoryJdbc4Impl"; } catch (ClassNotFoundException e2) { // java.sql.Wrapper is not present. This means we are running // JDBC 3.0 or earlier (probably JDK 1.5). Load the JDBC 3.0 // factory. return "org.olap4j.driver.xmla.FactoryJdbc3Impl"; } } } /** * Registers an instance of XmlaOlap4jDriver. * *

Called implicitly on class load, and implements the traditional * 'Class.forName' way of registering JDBC drivers. * * @throws SQLException on error */ private static void register() throws SQLException { DriverManager.registerDriver(new XmlaOlap4jDriver()); } public Connection connect(String url, Properties info) throws SQLException { // Checks if this driver handles this connection, exit otherwise. if (!XmlaOlap4jConnection.acceptsURL(url)) { return null; } // Parses the connection string Map map = XmlaOlap4jConnection.parseConnectString(url, info); // Creates a connection proxy XmlaOlap4jProxy proxy = createProxy(map); // returns a connection object to the java API return factory.newConnection(this, proxy, url, info); } public boolean acceptsURL(String url) throws SQLException { return XmlaOlap4jConnection.acceptsURL(url); } public DriverPropertyInfo[] getPropertyInfo( String url, Properties info) throws SQLException { List list = new ArrayList(); // Add the contents of info for (Map.Entry entry : info.entrySet()) { list.add( new DriverPropertyInfo( (String) entry.getKey(), (String) entry.getValue())); } // Next add standard properties return list.toArray(new DriverPropertyInfo[list.size()]); } /** * Returns the driver name. Not in the JDBC API. * @return Driver name */ String getName() { return XmlaOlap4jDriverVersion.NAME; } /** * Returns the driver version. Not in the JDBC API. * @return Driver version */ public String getVersion() { return XmlaOlap4jDriverVersion.VERSION; } public int getMajorVersion() { return XmlaOlap4jDriverVersion.MAJOR_VERSION; } public int getMinorVersion() { return XmlaOlap4jDriverVersion.MINOR_VERSION; } public boolean jdbcCompliant() { return false; } // for JDBC 4.1 public Logger getParentLogger() { return Logger.getLogger(""); } /** * Creates a Proxy with which to talk to send XML web-service calls. * The usual implementation of Proxy uses HTTP; there is another * implementation, for testing, which talks to mondrian's XMLA service * in-process. * * @param map Connection properties * @return A Proxy with which to submit XML requests */ protected XmlaOlap4jProxy createProxy(Map map) { String cookie = map.get(Property.TESTPROXYCOOKIE.name()); if (cookie != null) { XmlaOlap4jProxy proxy = PROXY_MAP.get(cookie); if (proxy != null) { return proxy; } } return new XmlaOlap4jHttpProxy(this); } /** * Returns a future object representing an asynchronous submission of an * XMLA request to a URL. * * @param proxy Proxy via which to send the request * @param serverInfos Server infos. * @param request Request * @return Future object from which the byte array containing the result * of the XMLA call can be obtained */ public static Future getFuture( final XmlaOlap4jProxy proxy, final XmlaOlap4jServerInfos serverInfos, final String request) { return executor.submit( new Callable() { public byte[] call() throws Exception { return proxy.get(serverInfos, request); } } ); } /** * For testing. Map from a cookie value (which is uniquely generated for * each test) to a proxy object. Uses a weak hash map so that, if the code * that created the proxy 'forgets' the cookie value, then the proxy can * be garbage-collected. */ public static final Map PROXY_MAP = Collections.synchronizedMap(new WeakHashMap()); /** * Generates and returns a unique string. * * @return unique string */ public static synchronized String nextCookie() { return "cookie" + nextCookie++; } /** * Properties supported by this driver. */ public enum Property { TESTPROXYCOOKIE( "String that uniquely identifies a proxy object via which to send " + "XMLA requests for testing purposes."), SERVER("URL of HTTP server"), DATABASE("Name of the database"), CATALOG("Catalog name"), SCHEMA("Name of the schema"), CACHE("Class name of the SOAP cache implementation"), ROLE("Comma separated list of roles this connection impersonates"), USER("Username to use when creating connections to the server."), PASSWORD("Password to use when creating connections to the server."); /** * Creates a property. * * @param description Description of property */ Property(String description) { Olap4jUtil.discard(description); } } } // End XmlaOlap4jDriver.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jDatabaseMetaData.java0000644000175000017500000011632411707255006025762 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jDatabaseMetaData.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.Member; import org.olap4j.metadata.XmlaConstants; import org.w3c.dom.Element; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implementation of {@link org.olap4j.OlapDatabaseMetaData} * for XML/A providers. * *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; * it is instantiated using {@link Factory#newDatabaseMetaData}.

* * @author jhyde * @version $Id: XmlaOlap4jDatabaseMetaData.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 23, 2007 */ abstract class XmlaOlap4jDatabaseMetaData implements OlapDatabaseMetaData { final XmlaOlap4jConnection olap4jConnection; /** * Creates an XmlaOlap4jDatabaseMetaData. * *

Note that this constructor should make zero non-trivial calls, which * could cause deadlocks due to java.sql.DriverManager synchronization * issues. * * @param olap4jConnection Connection */ XmlaOlap4jDatabaseMetaData( XmlaOlap4jConnection olap4jConnection) { this.olap4jConnection = olap4jConnection; } private ResultSet getMetadata( XmlaOlap4jConnection.MetadataRequest metadataRequest, Object... patternValues) throws OlapException { final Map overrides = Collections.emptyMap(); return getMetadata( metadataRequest, overrides, patternValues); } /** * Executes a metadata query and returns the result as a JDBC * {@link ResultSet}. * * @param metadataRequest Name of the metadata request. Corresponds to the * XMLA method name, e.g. "MDSCHEMA_CUBES" * * @param overrides Map of metadata columns to forced values. Used * to override the value returned by the server for a list of * columns. * * @param patternValues Array of alternating parameter name and value * pairs. If the parameter value is null, it is ignored. * * @return Result set of metadata * * @throws org.olap4j.OlapException on error */ private ResultSet getMetadata( XmlaOlap4jConnection.MetadataRequest metadataRequest, Map overrides, Object... patternValues) throws OlapException { assert patternValues.length % 2 == 0; final XmlaOlap4jConnection.Context context = new XmlaOlap4jConnection.Context( olap4jConnection, null, null, null, null, null, null, null); List patternValueList = new ArrayList(); Map predicateList = new HashMap(); for (int i = 0; i < patternValues.length; i += 2) { String name = (String) patternValues[i]; assert metadataRequest.getColumn(name) != null : "Request '" + metadataRequest + "' does not support column '" + name + "'"; Object value = patternValues[i + 1]; if (value == null) { // ignore } else if (value instanceof Wildcard) { final Wildcard wildcard = (Wildcard) value; if (wildcard.pattern.indexOf('%') < 0 && wildcard.pattern.indexOf('_') < 0) { patternValueList.add(name); patternValueList.add(wildcard.pattern); } else { String regexp = Olap4jUtil.wildcardToRegexp( Collections.singletonList(wildcard.pattern)); final Matcher matcher = Pattern.compile(regexp).matcher(""); predicateList.put(name, matcher); } } else { patternValueList.add(name); patternValueList.add((String) value); } } String request = olap4jConnection.generateRequest( context, metadataRequest, patternValueList.toArray( new String[patternValueList.size()])); final Element root = olap4jConnection.executeMetadataRequest(request); List> rowList = new ArrayList>(); rowLoop: for (Element row : XmlaOlap4jUtil.childElements(root)) { if (row.getNamespaceURI() != null && !row.getNamespaceURI().equals( "urn:schemas-microsoft-com:xml-analysis:rowset")) { // Ignore any vendor specific namespaced elements that // are not part of the rowset namespace continue; } final ArrayList valueList = new ArrayList(); for (Map.Entry entry : predicateList.entrySet()) { final String column = entry.getKey(); final String value = XmlaOlap4jUtil.stringElement(row, column); final Matcher matcher = entry.getValue(); if (!matcher.reset(value).matches()) { continue rowLoop; } } for (XmlaOlap4jConnection.MetadataColumn column : metadataRequest.columns) { if (overrides.containsKey(column)) { valueList.add(overrides.get(column)); } else { final String value = XmlaOlap4jUtil.stringElement(row, column.xmlaName); valueList.add(value); } } rowList.add(valueList); } List headerList = new ArrayList(); for (XmlaOlap4jConnection.MetadataColumn column : metadataRequest.columns) { headerList.add(column.name); } return olap4jConnection.factory.newFixedResultSet( olap4jConnection, headerList, rowList); } /** * Converts a string to a wildcard object. * * @param pattern String pattern * @return wildcard object, or null if pattern was null */ private Wildcard wildcard(String pattern) { return pattern == null ? null : new Wildcard(pattern); } // implement DatabaseMetaData public boolean allProceduresAreCallable() throws SQLException { throw new UnsupportedOperationException(); } public boolean allTablesAreSelectable() throws SQLException { throw new UnsupportedOperationException(); } public String getURL() throws SQLException { return olap4jConnection.getURL(); } public String getUserName() throws SQLException { throw new UnsupportedOperationException(); } public boolean isReadOnly() throws SQLException { // olap4j does not currently support writeback return true; } public boolean nullsAreSortedHigh() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullsAreSortedLow() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullsAreSortedAtStart() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullsAreSortedAtEnd() throws SQLException { throw new UnsupportedOperationException(); } public String getDatabaseProductName() throws SQLException { final ResultSet rs = this.getDatabaseProperties(null, null); try { while (rs.next()) { if (rs.getString( XmlaConstants.Literal.PROPERTY_NAME.name()) .equals("ProviderName")) { return rs.getString("PROPERTY_VALUE"); } } return ""; } finally { rs.close(); } } public String getDatabaseProductVersion() throws SQLException { final ResultSet rs = this.getDatabaseProperties(null, null); try { while (rs.next()) { if (rs.getString( XmlaConstants.Literal.PROPERTY_NAME.name()) .equals("ProviderVersion")) { return rs.getString("PROPERTY_VALUE"); } } return ""; } finally { rs.close(); } } public String getDriverName() throws SQLException { return olap4jConnection.driver.getName(); } public String getDriverVersion() throws SQLException { return olap4jConnection.driver.getVersion(); } public int getDriverMajorVersion() { return olap4jConnection.driver.getMajorVersion(); } public int getDriverMinorVersion() { return olap4jConnection.driver.getMinorVersion(); } public boolean usesLocalFiles() throws SQLException { throw new UnsupportedOperationException(); } public boolean usesLocalFilePerTable() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMixedCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesUpperCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesLowerCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesMixedCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public String getIdentifierQuoteString() throws SQLException { throw new UnsupportedOperationException(); } public String getSQLKeywords() throws SQLException { throw new UnsupportedOperationException(); } public String getNumericFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getStringFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getSystemFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getTimeDateFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getSearchStringEscape() throws SQLException { throw new UnsupportedOperationException(); } public String getExtraNameCharacters() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsAlterTableWithAddColumn() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsAlterTableWithDropColumn() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsColumnAliasing() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullPlusNonNullIsNull() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsConvert() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsConvert( int fromType, int toType) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsTableCorrelationNames() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsDifferentTableCorrelationNames() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsExpressionsInOrderBy() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOrderByUnrelated() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGroupBy() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGroupByUnrelated() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGroupByBeyondSelect() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsLikeEscapeClause() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMultipleResultSets() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMultipleTransactions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsNonNullableColumns() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMinimumSQLGrammar() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCoreSQLGrammar() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsExtendedSQLGrammar() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsANSI92EntryLevelSQL() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsANSI92IntermediateSQL() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsANSI92FullSQL() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsIntegrityEnhancementFacility() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOuterJoins() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsFullOuterJoins() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsLimitedOuterJoins() throws SQLException { throw new UnsupportedOperationException(); } public String getSchemaTerm() throws SQLException { throw new UnsupportedOperationException(); } public String getProcedureTerm() throws SQLException { throw new UnsupportedOperationException(); } public String getCatalogTerm() throws SQLException { throw new UnsupportedOperationException(); } public boolean isCatalogAtStart() throws SQLException { throw new UnsupportedOperationException(); } public String getCatalogSeparator() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInDataManipulation() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInProcedureCalls() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInTableDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInIndexDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInDataManipulation() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInProcedureCalls() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInTableDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInIndexDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsPositionedDelete() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsPositionedUpdate() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSelectForUpdate() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsStoredProcedures() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInComparisons() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInExists() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInIns() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInQuantifieds() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCorrelatedSubqueries() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsUnion() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsUnionAll() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenCursorsAcrossCommit() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenCursorsAcrossRollback() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenStatementsAcrossCommit() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenStatementsAcrossRollback() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxBinaryLiteralLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxCharLiteralLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInGroupBy() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInIndex() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInOrderBy() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInSelect() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInTable() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxConnections() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxCursorNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxIndexLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxSchemaNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxProcedureNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxCatalogNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxRowSize() throws SQLException { throw new UnsupportedOperationException(); } public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxStatementLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxStatements() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxTableNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxTablesInSelect() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxUserNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getDefaultTransactionIsolation() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsTransactions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsTransactionIsolationLevel(int level) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsDataManipulationTransactionsOnly() throws SQLException { throw new UnsupportedOperationException(); } public boolean dataDefinitionCausesTransactionCommit() throws SQLException { throw new UnsupportedOperationException(); } public boolean dataDefinitionIgnoredInTransactions() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getProcedures( String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getProcedureColumns( String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getTables( String catalog, String schemaPattern, String tableNamePattern, String types[]) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getSchemas() throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_SCHEMATA); } public ResultSet getCatalogs() throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_CATALOGS); } public ResultSet getTableTypes() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getColumns( String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getColumnPrivileges( String catalog, String schema, String table, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getTablePrivileges( String catalog, String schemaPattern, String tableNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getBestRowIdentifier( String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getVersionColumns( String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getPrimaryKeys( String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getImportedKeys( String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getExportedKeys( String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getCrossReference( String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getTypeInfo() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getIndexInfo( String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsResultSetType(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsResultSetConcurrency( int type, int concurrency) throws SQLException { throw new UnsupportedOperationException(); } public boolean ownUpdatesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean ownDeletesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean ownInsertsAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean othersUpdatesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean othersDeletesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean othersInsertsAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean updatesAreDetected(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean deletesAreDetected(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean insertsAreDetected(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsBatchUpdates() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getUDTs( String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { throw new UnsupportedOperationException(); } public OlapConnection getConnection() { return olap4jConnection; } public boolean supportsSavepoints() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsNamedParameters() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMultipleOpenResults() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGetGeneratedKeys() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getSuperTypes( String catalog, String schemaPattern, String typeNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getSuperTables( String catalog, String schemaPattern, String tableNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getAttributes( String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsResultSetHoldability(int holdability) throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetHoldability() throws SQLException { throw new UnsupportedOperationException(); } public int getDatabaseMajorVersion() throws SQLException { throw Olap4jUtil.needToImplement(this); } public int getDatabaseMinorVersion() throws SQLException { throw Olap4jUtil.needToImplement(this); } public int getJDBCMajorVersion() throws SQLException { // this driver supports jdbc 3.0 and jdbc 4.0 // FIXME: should return 3 if the current connection is jdbc 3.0 return 4; } public int getJDBCMinorVersion() throws SQLException { // this driver supports jdbc 3.0 and jdbc 4.0 return 0; } public int getSQLStateType() throws SQLException { throw new UnsupportedOperationException(); } public boolean locatorsUpdateCopy() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsStatementPooling() throws SQLException { throw new UnsupportedOperationException(); } // implement java.sql.Wrapper // straightforward implementation of unwrap and isWrapperFor, since this // class already implements the interface they most likely require: // DatabaseMetaData and OlapDatabaseMetaData public T unwrap(Class iface) throws SQLException { if (iface.isInstance(this)) { return iface.cast(this); } throw getHelper().createException( "does not implement '" + iface + "'"); } /** * Returns the error-handler. * * @return Error handler */ private XmlaHelper getHelper() { return olap4jConnection.helper; } public boolean isWrapperFor(Class iface) throws SQLException { return iface.isInstance(this); } // implement OlapDatabaseMetaData public Set getSupportedCellSetListenerGranularities() throws OlapException { return Collections.emptySet(); } public ResultSet getActions( String catalog, String schemaPattern, String cubeNamePattern, String actionNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_ACTIONS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "ACTION_NAME", wildcard(actionNamePattern)); } public ResultSet getDatabases() throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.DISCOVER_DATASOURCES); } public ResultSet getLiterals() throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.DISCOVER_LITERALS); } public ResultSet getDatabaseProperties( String dataSourceName, String propertyNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.DISCOVER_PROPERTIES); } public ResultSet getProperties( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelUniqueName, String memberUniqueName, String propertyNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_PROPERTIES, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", dimensionUniqueName, "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, "LEVEL_UNIQUE_NAME", levelUniqueName, "MEMBER_UNIQUE_NAME", memberUniqueName, "PROPERTY_NAME", wildcard(propertyNamePattern)); } public String getMdxKeywords() throws OlapException { final XmlaOlap4jConnection.MetadataRequest metadataRequest = XmlaOlap4jConnection.MetadataRequest.DISCOVER_KEYWORDS; final XmlaOlap4jConnection.Context context = new XmlaOlap4jConnection.Context( olap4jConnection, null, null, null, null, null, null, null); String request = olap4jConnection.generateRequest( context, metadataRequest, new Object[0]); final Element root = olap4jConnection.executeMetadataRequest(request); StringBuilder buf = new StringBuilder(); for (Element row : XmlaOlap4jUtil.childElements(root)) { if (buf.length() > 0) { buf.append(','); } final String keyword = XmlaOlap4jUtil.stringElement(row, "Keyword"); buf.append(keyword); } return buf.toString(); } public ResultSet getCubes( String catalog, String schemaPattern, String cubeNamePattern) throws OlapException { // XMLA doesn't support drillthrough so override // whatever the server returns. final Map overrides = new HashMap(); overrides.put( XmlaOlap4jConnection.MetadataRequest .MDSCHEMA_CUBES.getColumn("IS_DRILLTHROUGH_ENABLED"), "false"); return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_CUBES, overrides, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern)); } public ResultSet getDimensions( String catalog, String schemaPattern, String cubeNamePattern, String dimensionNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_DIMENSIONS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_NAME", wildcard(dimensionNamePattern)); } public ResultSet getOlapFunctions( String functionNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_FUNCTIONS, "FUNCTION_NAME", wildcard(functionNamePattern)); } public ResultSet getHierarchies( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_HIERARCHIES, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", dimensionUniqueName, "HIERARCHY_NAME", wildcard(hierarchyNamePattern)); } public ResultSet getMeasures( String catalog, String schemaPattern, String cubeNamePattern, String measureNamePattern, String measureUniqueName) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEASURES, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "MEASURE_NAME", wildcard(measureNamePattern), "MEASURE_UNIQUE_NAME", measureUniqueName); } public ResultSet getMembers( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelUniqueName, String memberUniqueName, Set treeOps) throws OlapException { String treeOpString; if (treeOps != null) { int op = 0; for (Member.TreeOp treeOp : treeOps) { op |= treeOp.xmlaOrdinal(); } treeOpString = String.valueOf(op); } else { treeOpString = null; } return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", dimensionUniqueName, "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, "LEVEL_UNIQUE_NAME", levelUniqueName, "MEMBER_UNIQUE_NAME", memberUniqueName, "TREE_OP", treeOpString); } public ResultSet getLevels( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_LEVELS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", dimensionUniqueName, "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, "LEVEL_NAME", wildcard(levelNamePattern)); } public ResultSet getSets( String catalog, String schemaPattern, String cubeNamePattern, String setNamePattern) throws OlapException { return getMetadata( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_SETS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "SET_NAME", wildcard(setNamePattern)); } /** * Wrapper which indicates that a restriction is to be treated as a * SQL-style wildcard match. */ static class Wildcard { final String pattern; /** * Creates a Wildcard. * * @param pattern Pattern */ Wildcard(String pattern) { assert pattern != null; this.pattern = pattern; } } } // End XmlaOlap4jDatabaseMetaData.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/0000755000175000017500000000000011542614630021151 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/XmlaOlap4jShaEncoder.java0000644000175000017500000000451211707255004025724 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jShaEncoder.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * SHA encoder to create unique hash strings for cache elements. * * @author Luc Boudreau * @version $Id: XmlaOlap4jShaEncoder.java 482 2012-01-05 23:27:27Z jhyde $ */ class XmlaOlap4jShaEncoder { private static String convertToHex(byte[] data) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < data.length; i++) { int halfbyte = (data[i] >>> 4) & 0x0F; int two_halfs = 0; do { if ((0 <= halfbyte) && (halfbyte <= 9)) { buf.append((char) ('0' + halfbyte)); } else { buf.append((char) ('a' + (halfbyte - 10))); } halfbyte = data[i] & 0x0F; } while (two_halfs++ < 1); } return buf.toString(); } public static String encodeSha1(String text) { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e1) { throw new RuntimeException(e1); } } byte[] sha1hash = new byte[40]; md.update(text.getBytes(), 0, text.length()); sha1hash = md.digest(); return convertToHex(sha1hash); } } // End XmlaOlap4jShaEncoder.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/package.html0000644000175000017500000000010711421322450023420 0ustar drazzibdrazzib Provides SOAP caching functionality. olap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/XmlaOlap4jNamedMemoryCache.java0000644000175000017500000001740711707255004027061 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jNamedMemoryCache.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import org.olap4j.impl.Olap4jUtil; import java.net.URL; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** *

Implementation of the XMLA SOAP cache that places its cache entries * in memory for later use. It is thread safe and at static class level. * *

It supports cache sharing through the Name property. * *

All parameters are optional. * *

    *
  • NAME
    A unique identifier which allows two connections * to share a same cache space. Setting this to an already existing cache * space will cause the cache manager to ignore other configuration properties, * such as eviction mode and so on. Not setting this property will * assign a random name to the cache space, thus creating a unique space.
  • *
  • SIZE
    The number of entries to maintain in cache under * the given cache name.
  • *
  • TIMEOUT
    The number of seconds to maintain entries in * cache before expiration.
  • *
  • MODE
    Supported eviction modes are LIFO (last in first out), * FIFO (first in first out), LFU (least frequently used) and MFU * (most frequently used)
  • *
* * @see XmlaOlap4jNamedMemoryCache.Property * @version $Id: XmlaOlap4jNamedMemoryCache.java 482 2012-01-05 23:27:27Z jhyde $ */ public class XmlaOlap4jNamedMemoryCache implements XmlaOlap4jCache { /** *

Thread safe hashmap which will be used to keep track of * the current caches. The unique ID is the URL. */ private static Map caches = null; /** * Properties which will be considered for configuration. * *

All parameters are optional. */ public static enum Property { /** * A unique identifier which allows two connections to share a same * cache space. Setting this to an already existing cache * space will cause the cache manager to ignore other configuration * properties, such as eviction mode and so on. Not setting this * property will assign a random name to the cache space, thus creating * a unique space. */ NAME("Name of a cache to create or to share."), /** * The number of entries to maintain in cache under * the given cache name. */ SIZE( "Maximum number of SOAP requests which will be cached under the " + "given cache name."), /** * The number of seconds to maintain * entries in cache before expiration. */ TIMEOUT( "Maximum TTL of SOAP requests which will be cached under the given " + "cache name."), /** * Eviction mode. Supported eviction modes are * LIFO (last in first out), FIFO (first in first out), * LFU (least frequently used) and MFU (most frequently used). */ MODE("Eviction mode to set to the given cache name."); /** * Creates a property. * * @param description Description of property */ Property(String description) { Olap4jUtil.discard(description); } } /** * Defines the supported eviction modes. */ public static enum Mode { /** Last-in, first-out. */ LIFO, /** First-in, first-out. */ FIFO, /** Least-frequently used. */ LFU, /** Most-frequently used. */ MFU } /** * Makes sure that the cache is not accessed before it is configured. */ private boolean initDone = false; /** * Default constructor which instantiates the concurrent hash map. */ public XmlaOlap4jNamedMemoryCache() { XmlaOlap4jNamedMemoryCache.initCaches(); } /** * Initializes the caches in a static and thread safe way. */ private static synchronized void initCaches() { if (caches == null) { caches = new ConcurrentHashMap< String, XmlaOlap4jConcurrentMemoryCache>(); } } // implement XmlaOlap4jCache public String setParameters( Map config, Map props) { String refId; // Make sure there's a name for the cache. Generate a // random one if needed. if (props.containsKey( XmlaOlap4jNamedMemoryCache.Property.NAME.name())) { refId = (String) props.get( XmlaOlap4jNamedMemoryCache.Property.NAME.name()); } else { refId = String.valueOf(UUID.randomUUID()); props.put(XmlaOlap4jNamedMemoryCache.Property.NAME.name(), refId); } // Wait for exclusive access to the caches synchronized (caches) { // Create a cache for this URL if it is not created yet if (!caches.containsKey( props.get( XmlaOlap4jNamedMemoryCache.Property.NAME.name()))) { caches.put( (String) props.get( XmlaOlap4jNamedMemoryCache.Property.NAME.name()), new XmlaOlap4jConcurrentMemoryCache(props)); } } // Mark this cache as inited. this.initDone = true; // Give back the reference id. return refId; } // implement XmlaOlap4jCache public byte[] get( String id, URL url, byte[] request) throws XmlaOlap4jInvalidStateException { this.validateState(); // Wait for exclusive access to the caches synchronized (caches) { if (caches.containsKey(id)) { return caches.get(id).get(url, request); } else { throw new XmlaOlap4jInvalidStateException(); } } } // implement XmlaOlap4jCache public void put( String id, URL url, byte[] request, byte[] response) throws XmlaOlap4jInvalidStateException { this.validateState(); // Wait for exclusive access to the caches synchronized (caches) { if (caches.containsKey(id)) { caches.get(id).put(url, request, response); } else { throw new XmlaOlap4jInvalidStateException(); } } } // implement XmlaOlap4jCache public void flushCache() { // Wait for exclusive access to the caches synchronized (caches) { caches.clear(); } } /** * Helper method to validate that the cache is initialized. * * @throws XmlaOlap4jInvalidStateException When the cache is not initialized. */ private void validateState() throws XmlaOlap4jInvalidStateException { if (!this.initDone) { throw new XmlaOlap4jInvalidStateException(); } } } // End XmlaOlap4jNamedMemoryCache.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/XmlaOlap4jInvalidStateException.java0000644000175000017500000000252211707255004030156 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jInvalidStateException.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import org.olap4j.OlapException; /** *

Internal exception which gets thrown when operations to the cache * are performed but it hasn't been initialized. * * @author Luc Boudreau * @version $Id: XmlaOlap4jInvalidStateException.java 482 2012-01-05 23:27:27Z jhyde $ */ public class XmlaOlap4jInvalidStateException extends OlapException { private static final long serialVersionUID = 7265273715459263740L; } // End XmlaOlap4jInvalidStateException.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCache.java0000644000175000017500000000770111707255004024717 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCache.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import org.olap4j.OlapException; import java.net.URL; import java.util.Map; /** * XMLA driver cache. Implementations will have to declare those methods. * *

The XMLA driver will call the cache before each SOAP request to see * if it wasn't sent previously and if a SOAP response doesn't already * exist in it. * *

Any implementations have to declare a constructor which takes a String * as a parameter. This string value is the unique name of the connection * which triggered the request. * * @author Luc Boudreau * @version $Id: XmlaOlap4jCache.java 482 2012-01-05 23:27:27Z jhyde $ */ public interface XmlaOlap4jCache { /** * Fetches a SOAP response from the cache. Returns null * if there are no cached response corresponding to the SOAP * message and the URL. * * @param id The connection unique name which called this cache. * @param url The URL where the SOAP message was sent. * @param request The SOAP complete message. * * @throws OlapException when operations to the cache are * performed but it hasn't been initialized. Make sure you * call the setParameters(Map, Map) method. * * @return The SOAP response, null if there are no corresponding * response in the cache. */ public byte[] get( String id, URL url, byte[] request) throws OlapException; /** * Adds a SOAP response to the cache. It has to be relative to the * URL of the SOAP service. * * @param id The connection unique name which called this cache. * @param url The URL of the SOAP endpoint. * @param request The full SOAP message from which we want to cache its * response. * @param response The response to cache. * * @throws OlapException when operations to the cache are * performed but it hasn't been initialized. Make sure you * call the setParameters(Map, Map) method. */ public void put( String id, URL url, byte[] request, byte[] response) throws OlapException; /** * Tells the cache to flush all cached entries. */ public void flushCache(); /** * Convenience method to receive custom properties. * *

The XMLA driver takes cache properties as * "Cache.[property name]=[value]" in its JDBC url. All those * properties should be striped of their "Cache." prefix and * sent to this method as the props parameter. * *

Also, the complete map of the current connection * should be passed as the config parameter. * * @param config The complete configuration parameters which were used to * create the current connection. * @param props The properties received from the JDBC url. * @return Returns a string object which gives a reference id to the * caller for future use. This id has to be passed along with any future * get and put requests. */ public String setParameters( Map config, Map props); } // End XmlaOlap4jCache.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCacheElement.java0000644000175000017500000000440411707255004026226 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCacheElement.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import java.util.Calendar; import java.util.concurrent.atomic.AtomicLong; /** * Internal POJO class definition for the XmlaOlap4jMemoryCache. * * @author Luc Boudreau * @version $Id: XmlaOlap4jCacheElement.java 482 2012-01-05 23:27:27Z jhyde $ */ class XmlaOlap4jCacheElement { /** * The time in miliseconds when the entry was created. */ private AtomicLong timestamp = new AtomicLong(Calendar.getInstance().getTimeInMillis()); /** * This holds the number of times the entry was used. */ private AtomicLong hitMeter = new AtomicLong(new Long("1")); /** * The cached SOAP response. */ private byte[] response = null; /** * Updates this element's internal timestamp. */ public void refreshTimestamp() { this.timestamp.compareAndSet( this.timestamp.longValue(), Calendar.getInstance().getTimeInMillis()); } /** * Updates this element's internal timestamp. */ public void incrementHitCount() { this.hitMeter.incrementAndGet(); } public byte[] getResponse() { return response; } public void setResponse(byte[] response) { this.response = response; } public AtomicLong getTimestamp() { return timestamp; } public AtomicLong getHitCount() { return hitMeter; } } // End XmlaOlap4jCacheElement.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/cache/XmlaOlap4jConcurrentMemoryCache.java0000644000175000017500000002516411707255004030156 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jConcurrentMemoryCache.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.cache; import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache.Mode; import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache.Property; import org.olap4j.impl.Olap4jUtil; import java.net.URL; import java.util.Calendar; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; /** * Thread-safe cache object which supports concurrent access. * *

It keeps its cache element objects in memory in an internal hash * table. Instantiate it and use. As simple as that. * * @author Luc Boudreau * @version $Id: XmlaOlap4jConcurrentMemoryCache.java 482 2012-01-05 23:27:27Z jhyde $ */ class XmlaOlap4jConcurrentMemoryCache { /** * Default cache timeout (1 minute). The value is in seconds. */ private static final int DEFAULT_CACHE_TIMEOUT = 60; /** * Default cache size (10). */ private static final int DEFAULT_CACHE_SIZE = 10; /** * Default eviction mode (LFU). */ private static final Mode DEFAULT_EVICTION_MODE = Mode.LFU; /** * Thread-safe hashmap which will be used as a cache. * *

The cache is a map structured as follows: * *

    *
  • key -> String : SHA-1 encoding of the full URL
  • *
*/ private Map cacheEntries = new ConcurrentHashMap(); /** * Cache size. */ private int cacheSize = DEFAULT_CACHE_SIZE; /** * Eviction mode. */ private Mode evictionMode = DEFAULT_EVICTION_MODE; /** * Cache timeout, in seconds. */ private int cacheTimeout = DEFAULT_CACHE_TIMEOUT; /** * Creates an XmlaOlap4jConcurrentMemoryCache. * * @param props Properties * @throws IllegalArgumentException */ public XmlaOlap4jConcurrentMemoryCache( Map props) throws IllegalArgumentException { for (Entry entry : props.entrySet()) { if (Property.SIZE.name().equalsIgnoreCase( entry.getKey().toString())) { this.setCacheSize( Integer.parseInt(entry.getValue().toString())); } else if (Property.TIMEOUT.name().equalsIgnoreCase( entry.getKey().toString())) { this.setCacheTimeout( Integer.parseInt(entry.getValue().toString())); } else if (Property.MODE.name().equalsIgnoreCase( entry.getKey().toString())) { this.setCacheMode( entry.getValue().toString()); } } } /** * Sets the number of cached entries. * @param size The number of cached entries. */ private void setCacheSize(int size) { if (size <= 0) { throw new IllegalArgumentException( "Cache size must be positive, but was " + size); } this.cacheSize = size; } /** * Sets the eviction mode. * * @param mode Eviction mode */ private void setCacheMode(String mode) { if (Mode.valueOf(mode) == null) { throw new IllegalArgumentException( "The XmlaOlap4jMemoryCache mode has to be one of " + Mode.class.getName()); } this.evictionMode = Mode.valueOf(mode); } /** * Sets the cache expiration timeout. * * @param seconds The number of seconds to hold the entries in cache. */ private void setCacheTimeout(int seconds) { if (seconds <= 0) { throw new IllegalArgumentException( "Cache timeout must be positive, but was " + seconds); } this.cacheTimeout = seconds; } byte[] get( final URL url, final byte[] request) { // Take the cache for ourself synchronized (this.cacheEntries) { // Clean expired values cleanExpired(false); // Extract the data from the cache XmlaOlap4jCacheElement entry = this.cacheEntries.get( XmlaOlap4jShaEncoder.encodeSha1( url.toExternalForm() + new String(request))); // Increment its counter if (entry != null) { entry.incrementHitCount(); entry.refreshTimestamp(); } // Return a copy to prevent corruption return entry != null ? new String(entry.getResponse()).getBytes() : null; } } void put( final URL url, final byte[] request, final byte[] response) { // Take the cache for ourself synchronized (this.cacheEntries) { // Make some cleanup cleanExpired(true); if (this.cacheEntries.size() < cacheSize) { // Create the entry XmlaOlap4jCacheElement entry = new XmlaOlap4jCacheElement(); entry.setResponse(response); this.cacheEntries.put( XmlaOlap4jShaEncoder.encodeSha1( String.valueOf(url.toExternalForm()) + new String(request)), entry); } else { throw new RuntimeException("Concurrency error detected."); } } } /** * Cleans expired cache entries. * * @param makeRoom Whether to make room for later appending by * evicting an entry based on the selected eviction mode. */ private void cleanExpired(boolean makeRoom) { final String toBeEvicted; switch (evictionMode) { case FIFO: case LIFO: toBeEvicted = timeBasedEviction(makeRoom); break; case LFU: case MFU: toBeEvicted = hitBasedEviction(makeRoom); break; default: throw Olap4jUtil.unexpected(evictionMode); } // Make some space if required if (makeRoom && this.cacheEntries.size() >= cacheSize && toBeEvicted != null) { this.cacheEntries.remove(toBeEvicted); } } /** * Scans for the key of the cache entry to be evicted based * on the selected time based eviction mode. * * @param makeRoom Whether to make room for later appending by * evicting an entry. if false is specified, there might not * be an evicted entry if the cache is not full. * @return The key of the entry to remove, null otherwise. */ private String timeBasedEviction(boolean makeRoom) { // This is a flag to find the oldest entry. long currentEvictedTimestamp = evictionMode == Mode.LIFO ? Long.MAX_VALUE : Long.MIN_VALUE; String toBeEvicted = null; // Iterate over entries for (Entry entry : this.cacheEntries.entrySet()) { // Check if not expired if (Calendar.getInstance().getTimeInMillis() > (entry.getValue().getTimestamp().longValue() + (cacheTimeout * 1000))) { // Evicts it. this.cacheEntries.remove(entry.getKey()); continue; } // Checks if this is the oldest entry. if ((makeRoom && (evictionMode == XmlaOlap4jNamedMemoryCache.Mode.LIFO && entry.getValue().getTimestamp().longValue() < currentEvictedTimestamp)) || (makeRoom && (evictionMode == XmlaOlap4jNamedMemoryCache.Mode.FIFO && entry.getValue().getTimestamp().longValue() > currentEvictedTimestamp))) { currentEvictedTimestamp = entry.getValue().getTimestamp().longValue(); toBeEvicted = entry.getKey(); } } return toBeEvicted; } /** * Scans for the key of the cache entry to be evicted based * on the selected hit based eviction mode. * * @param makeRoom Whether to make room for later appending by evicting an * entry. If false, there might not be an evicted entry if the cache is not * full * * @return The key of the entry to remove, null otherwise. */ private String hitBasedEviction(boolean makeRoom) { // Flag to find the oldest entry. long currentEvictedHits = (evictionMode == Mode.LFU) ? Long.MAX_VALUE : Long.MIN_VALUE; String toBeEvicted = null; // Iterates over entries for (Entry entry : this.cacheEntries.entrySet()) { // Checks if not expired if (Calendar.getInstance().getTimeInMillis() > (entry.getValue().getTimestamp().longValue() + (cacheTimeout * 1000))) { // Evicts it this.cacheEntries.remove(entry.getKey()); continue; } // Checks if this is the oldest entry. if ((makeRoom && (evictionMode == Mode.LFU && entry.getValue().getHitCount().longValue() < currentEvictedHits)) || (makeRoom && (evictionMode == XmlaOlap4jNamedMemoryCache.Mode.MFU && entry.getValue().getHitCount().longValue() > currentEvictedHits))) { currentEvictedHits = entry.getValue().getHitCount().longValue(); toBeEvicted = entry.getKey(); } } return toBeEvicted; } } // End XmlaOlap4jConcurrentMemoryCache.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCell.java0000644000175000017500000000643211707255006023532 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCell.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import org.olap4j.impl.UnmodifiableArrayMap; import org.olap4j.metadata.Property; import java.sql.ResultSet; import java.util.List; import java.util.Map; /** * Implementation of {@link org.olap4j.Cell} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jCell.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 5, 2007 */ class XmlaOlap4jCell implements Cell { private final XmlaOlap4jCellSet cellSet; private final int ordinal; private final Object value; private final String formattedValue; private final Map propertyValues; XmlaOlap4jCell( XmlaOlap4jCellSet cellSet, int ordinal, Object value, String formattedValue, Map propertyValues) { this.cellSet = cellSet; this.ordinal = ordinal; this.value = value; this.formattedValue = formattedValue; // Use an ArrayMap for memory efficiency, because cells // typically have few properties, but there are a lot of cells this.propertyValues = UnmodifiableArrayMap.of(propertyValues); } public CellSet getCellSet() { return cellSet; } public int getOrdinal() { return ordinal; } public List getCoordinateList() { return cellSet.ordinalToCoordinates(ordinal); } public Object getPropertyValue(Property property) { return propertyValues.get(property); } public boolean isEmpty() { // FIXME return isNull(); } public boolean isError() { return false; } public boolean isNull() { return value == null; } public double getDoubleValue() throws OlapException { if (value instanceof Number) { return ((Number) value).doubleValue(); } else { return Double.valueOf(String.valueOf(value)); } } public String getErrorText() { return null; // FIXME: } public Object getValue() { return value; } public String getFormattedValue() { return formattedValue; } public ResultSet drillThrough() throws OlapException { throw new UnsupportedOperationException(); } public void setValue( Object value, AllocationPolicy allocationPolicy, Object... allocationArgs) { throw new UnsupportedOperationException(); } } // End XmlaOlap4jCell.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java0000644000175000017500000001413611713757552024237 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCatalog.java 488 2012-01-18 21:28:50Z pstoellberger $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapDatabaseMetaData; import org.olap4j.OlapException; import org.olap4j.impl.Named; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; import java.sql.SQLException; import java.util.List; /** * Implementation of {@link org.olap4j.metadata.Catalog} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jCatalog.java 488 2012-01-18 21:28:50Z pstoellberger $ * @since May 23, 2007 */ class XmlaOlap4jCatalog implements Catalog, Named { final XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData; private final String name; final DeferredNamedListImpl schemas; private final XmlaOlap4jDatabase database; private List roles; XmlaOlap4jCatalog( XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData, XmlaOlap4jDatabase database, String name, List roles) { this.database = database; assert olap4jDatabaseMetaData != null; assert name != null; this.olap4jDatabaseMetaData = olap4jDatabaseMetaData; this.name = name; this.roles = roles; // Some servers don't support MDSCHEMA_MDSCHEMATA, so we will // override the list class so it tries it first, and falls // back to the MDSCHEMA_CUBES trick, where ask for the cubes, // restricting results on the catalog, and while // iterating on the cubes, take the schema name from this recordset. // // Many servers (SSAS for example) won't support the schema name column // in the returned rowset. This has to be taken into account as well. this.schemas = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_SCHEMATA, new XmlaOlap4jConnection.Context( olap4jDatabaseMetaData.olap4jConnection, olap4jDatabaseMetaData, this, null, null, null, null, null), new XmlaOlap4jConnection.CatalogSchemaHandler(this.name), null) { private boolean useSchemata = false; @Override protected void populateList( NamedList list) throws OlapException { try { /* * Some OLAP servers don't support DBSCHEMA_SCHEMATA * so we fork the behavior here according to the * database product name. */ if (XmlaOlap4jCatalog.this.olap4jDatabaseMetaData .getDatabaseProductName().contains("Mondrian")) { this.useSchemata = true; } } catch (SQLException e1) { throw new OlapException( "Failed to obtain the database product name.", e1); } try { if (this.useSchemata) { super.populateList(list); return; } } catch (OlapException e) { // no op. we know how to fallback. useSchemata = false; } // Fallback to MDSCHEMA_CUBES trick populateInternal(list); } private void populateInternal( NamedList list) throws OlapException { XmlaOlap4jConnection conn = XmlaOlap4jCatalog.this .olap4jDatabaseMetaData.olap4jConnection; conn.populateList( list, new XmlaOlap4jConnection.Context( conn, conn.olap4jDatabaseMetaData, XmlaOlap4jCatalog.this, null, null, null, null, null), XmlaOlap4jConnection.MetadataRequest .MDSCHEMA_CUBES, new XmlaOlap4jConnection.CatalogSchemaHandler( XmlaOlap4jCatalog.this.name), new Object[0]); } }; } public int hashCode() { return name.hashCode(); } public boolean equals(Object obj) { if (obj instanceof XmlaOlap4jCatalog) { XmlaOlap4jCatalog that = (XmlaOlap4jCatalog) obj; return this.name.equals(that.name); } return false; } public NamedList getSchemas() throws OlapException { return Olap4jUtil.cast(schemas); } public String getName() { return name; } protected List getAvailableRoles() { return roles; } public OlapDatabaseMetaData getMetaData() { return olap4jDatabaseMetaData; } public XmlaOlap4jDatabase getDatabase() { return database; } } // End XmlaOlap4jCatalog.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jElement.java0000644000175000017500000000474111707255006024245 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jElement.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.impl.Named; import org.olap4j.metadata.MetadataElement; /** * Abstract implementation of {@link MetadataElement} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jElement.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 5, 2007 */ abstract class XmlaOlap4jElement implements MetadataElement, Named { protected final String uniqueName; protected final String name; protected final String caption; protected final String description; private int hash = 0; XmlaOlap4jElement( String uniqueName, String name, String caption, String description) { assert uniqueName != null; assert description != null; assert name != null; assert caption != null; this.description = description; this.uniqueName = uniqueName; this.caption = caption; this.name = name; } public String getName() { return name; } public String getUniqueName() { return uniqueName; } public String getCaption() { return caption; } public String getDescription() { return description; } public boolean isVisible() { return true; } public int hashCode() { // By the book implementation of a hash code identifier. if (this.hash == 0) { hash = (getClass().hashCode() << 8) ^ getUniqueName().hashCode(); } return hash; } // Keep this declaration abstract as a reminder to // overriding classes. public abstract boolean equals(Object obj); } // End XmlaOlap4jElement.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jDatabase.java0000644000175000017500000000744111707255006024360 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jDatabase.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapConnection; import org.olap4j.OlapException; import org.olap4j.impl.Named; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; import java.util.Collections; import java.util.List; /** * XMLA implementation of a database metadata object. * @version $Id: XmlaOlap4jDatabase.java 483 2012-01-05 23:43:18Z jhyde $ * @author LBoudreau */ class XmlaOlap4jDatabase implements Database, Named { private final NamedList catalogs; private final XmlaOlap4jConnection olap4jConnection; private final String name; private final String description; private final String providerName; private final String url; private final String dataSourceInfo; private final List providerType; private final List authenticationMode; public XmlaOlap4jDatabase( XmlaOlap4jConnection olap4jConnection, String name, String description, String providerName, String url, String dataSourceInfo, List providerType, List authenticationMode) { this.olap4jConnection = olap4jConnection; this.name = name; this.description = description; this.providerName = providerName; this.url = url; this.dataSourceInfo = dataSourceInfo; this.providerType = Collections.unmodifiableList(providerType); this.authenticationMode = Collections.unmodifiableList(authenticationMode); this.catalogs = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_CATALOGS, new XmlaOlap4jConnection.Context( olap4jConnection, (XmlaOlap4jDatabaseMetaData) olap4jConnection .getMetaData(), null, null, null, null, null, null), new XmlaOlap4jConnection.CatalogHandler(this), null); } public List getAuthenticationModes() throws OlapException { return authenticationMode; } public NamedList getCatalogs() throws OlapException { return Olap4jUtil.cast(catalogs); } public String getDescription() throws OlapException { return this.description; } public String getName() { return this.name; } public OlapConnection getOlapConnection() { return this.olap4jConnection; } public String getProviderName() throws OlapException { return this.providerName; } public List getProviderTypes() throws OlapException { return this.providerType; } public String getURL() throws OlapException { return this.url; } public String getDataSourceInfo() throws OlapException { return this.dataSourceInfo; } } // End XmlaOlap4jDatabase.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jSchema.java0000644000175000017500000000746611707255006024063 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jSchema.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.Named; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; import java.util.*; /** * Implementation of {@link org.olap4j.metadata.Schema} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jSchema.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 24, 2007 */ class XmlaOlap4jSchema implements Schema, Named { final XmlaOlap4jCatalog olap4jCatalog; private final String name; final NamedList cubes; private final NamedList sharedDimensions; XmlaOlap4jSchema( XmlaOlap4jCatalog olap4jCatalog, String name) throws OlapException { if (olap4jCatalog == null) { throw new NullPointerException("Catalog cannot be null."); } if (name == null) { throw new NullPointerException("Name cannot be null."); } this.olap4jCatalog = olap4jCatalog; this.name = name; // Dummy cube to own shared dimensions. final XmlaOlap4jCube sharedCube = new XmlaOlap4jCube(this, "", "", ""); final XmlaOlap4jConnection.Context context = new XmlaOlap4jConnection.Context( olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection, olap4jCatalog.olap4jDatabaseMetaData, olap4jCatalog, this, sharedCube, null, null, null); this.cubes = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_CUBES, context, new XmlaOlap4jConnection.CubeHandler(), null); String[] restrictions = { "CATALOG_NAME", olap4jCatalog.getName(), "SCHEMA_NAME", getName(), "CUBE_NAME", "" }; this.sharedDimensions = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_DIMENSIONS, context, new XmlaOlap4jConnection.DimensionHandler(sharedCube), restrictions); } public int hashCode() { return name.hashCode(); } public boolean equals(Object obj) { if (obj instanceof XmlaOlap4jSchema) { XmlaOlap4jSchema that = (XmlaOlap4jSchema) obj; return this.name.equals(that.name) && this.olap4jCatalog.equals(that.olap4jCatalog); } return false; } public Catalog getCatalog() { return olap4jCatalog; } public String getName() { return name; } public NamedList getCubes() throws OlapException { return Olap4jUtil.cast(cubes); } public NamedList getSharedDimensions() throws OlapException { return Olap4jUtil.cast(sharedDimensions); } public Collection getSupportedLocales() throws OlapException { return Collections.emptyList(); } } // End XmlaOlap4jSchema.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetAxisMetaData.java0000644000175000017500000000473311707255006026436 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCellSetAxisMetaData.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.Axis; import org.olap4j.CellSetAxisMetaData; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.Hierarchy; import org.olap4j.metadata.Property; import java.util.List; /** * Implementation of {@link org.olap4j.CellSetMetaData} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jCellSetAxisMetaData.java 482 2012-01-05 23:27:27Z jhyde $ * @since Nov 17, 2007 */ class XmlaOlap4jCellSetAxisMetaData implements CellSetAxisMetaData { private final Axis axis; private final List hierarchyList; private final List propertyList; XmlaOlap4jCellSetAxisMetaData( XmlaOlap4jConnection olap4jConnection, Axis axis, List hierarchyList, List propertyList) { this.axis = axis; this.hierarchyList = hierarchyList; this.propertyList = propertyList; } public Axis getAxisOrdinal() { return axis; } public List getHierarchies() { return hierarchyList; } public List getProperties() { return Olap4jUtil.cast(propertyList); } XmlaOlap4jCellSetMemberProperty lookupProperty( String hierarchyName, String tag) { for (XmlaOlap4jCellSetMemberProperty property : propertyList) { if (property.hierarchy.getName().equals(hierarchyName) && property.tag.equals(tag)) { return property; } } return null; } } // End XmlaOlap4jCellSetAxisMetaData.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCellProperty.java0000644000175000017500000000411111707255006025267 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCellProperty.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.impl.Named; import org.olap4j.metadata.Datatype; import org.olap4j.metadata.Property; import java.util.Set; /** * Implementation of {@link org.olap4j.metadata.Property} * for a cell in a cellset * from XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jCellProperty.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 8, 2007 */ class XmlaOlap4jCellProperty implements Property, Named { final String tag; final String propertyName; XmlaOlap4jCellProperty( String tag, String propertyName) { this.tag = tag; this.propertyName = propertyName; } public Datatype getDatatype() { return Datatype.STRING; } public Set getType() { return TypeFlag.CELL_TYPE_FLAG; } public String getName() { return propertyName; } public String getUniqueName() { return propertyName; } public String getCaption() { return propertyName; } public String getDescription() { return ""; } public ContentType getContentType() { return ContentType.REGULAR; } public boolean isVisible() { return true; } } // End XmlaOlap4jCellProperty.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaHelper.java0000644000175000017500000000434111707255006023015 0ustar drazzibdrazzib/* // $Id: XmlaHelper.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.Cell; import org.olap4j.OlapException; import java.sql.SQLException; /** * Helper class which encapsulates policies which are * common throughout a driver. These policies include exception handling * and factory methods. * * @author Luc Boudreau * @version $Id: XmlaHelper.java 482 2012-01-05 23:27:27Z jhyde $ */ public class XmlaHelper { public OlapException createException(String msg) { return new OlapException(msg); } public OlapException createException(Throwable cause) { return new OlapException(cause.getMessage(), cause); } public OlapException createException(String msg, Throwable cause) { return new OlapException(msg, cause); } public OlapException createException(Cell context, String msg) { OlapException exception = new OlapException(msg); exception.setContext(context); return exception; } public OlapException createException( Cell context, String msg, Throwable cause) { OlapException exception = new OlapException(msg, cause); exception.setContext(context); return exception; } public OlapException toOlapException(SQLException e) { if (e instanceof OlapException) { return (OlapException) e; } else { return new OlapException(null, e); } } } // End XmlaHelper.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jPreparedStatement.java0000644000175000017500000003632411707255006026305 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jPreparedStatement.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; import org.olap4j.type.*; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.*; import java.sql.Date; import java.util.*; /** * Implementation of {@link org.olap4j.PreparedOlapStatement} * for XML/A providers. * *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; * it is instantiated using {@link Factory#newPreparedStatement}.

* * @author jhyde * @version $Id: XmlaOlap4jPreparedStatement.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 12, 2007 */ abstract class XmlaOlap4jPreparedStatement extends XmlaOlap4jStatement implements PreparedOlapStatement, OlapParameterMetaData { final XmlaOlap4jCellSetMetaData cellSetMetaData; private final String mdx; /** * Creates an XmlaOlap4jPreparedStatement. * * @param olap4jConnection Connection * @param mdx MDX query string * @throws OlapException on error */ XmlaOlap4jPreparedStatement( XmlaOlap4jConnection olap4jConnection, String mdx) throws OlapException { super(olap4jConnection); // Execute a statement and steal its metadata. final OlapStatement statement = olap4jConnection.createStatement(); try { final CellSet cellSet = statement.executeOlapQuery(mdx); final XmlaOlap4jCellSetMetaData cellSetMetaData1 = (XmlaOlap4jCellSetMetaData) cellSet.getMetaData(); this.cellSetMetaData = cellSetMetaData1.cloneFor(this); cellSet.close(); statement.close(); } catch (SQLException e) { throw getHelper().createException( "Error while preparing statement '" + mdx + "'", e); } this.mdx = mdx; } /** * Returns the error-handler. * * @return Error handler */ private final XmlaHelper getHelper() { return olap4jConnection.helper; } // override OlapStatement public CellSet executeOlapQuery(String mdx) throws OlapException { return super.executeOlapQuery(mdx); } // implement PreparedOlapStatement public CellSet executeQuery() throws OlapException { return executeOlapQuery(mdx); } public OlapParameterMetaData getParameterMetaData() throws OlapException { return this; } public Cube getCube() { return cellSetMetaData.cube; } // implement PreparedStatement public int executeUpdate() throws SQLException { throw new UnsupportedOperationException(); } public void setNull(int parameterIndex, int sqlType) throws SQLException { getParameter(parameterIndex).setValue(null); } public void setBoolean(int parameterIndex, boolean x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setByte(int parameterIndex, byte x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setShort(int parameterIndex, short x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setInt(int parameterIndex, int x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setLong(int parameterIndex, long x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setFloat(int parameterIndex, float x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setDouble(int parameterIndex, double x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setBigDecimal( int parameterIndex, BigDecimal x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setString(int parameterIndex, String x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setBytes(int parameterIndex, byte x[]) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setDate(int parameterIndex, Date x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setTime(int parameterIndex, Time x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setTimestamp( int parameterIndex, Timestamp x) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setAsciiStream( int parameterIndex, InputStream x, int length) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setUnicodeStream( int parameterIndex, InputStream x, int length) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setBinaryStream( int parameterIndex, InputStream x, int length) throws SQLException { getParameter(parameterIndex).setValue(x); } public void unset(int parameterIndex) throws SQLException { getParameter(parameterIndex).unset(); } public boolean isSet(int parameterIndex) throws SQLException { return getParameter(parameterIndex).isSet(); } public void clearParameters() throws SQLException { throw new UnsupportedOperationException(); } public void setObject( int parameterIndex, Object x, int targetSqlType) throws SQLException { getParameter(parameterIndex).setValue(x); } public void setObject(int parameterIndex, Object x) throws SQLException { final Parameter parameter = getParameter(parameterIndex); parameter.setValue(x); } public boolean execute() throws SQLException { throw new UnsupportedOperationException(); } public void addBatch() throws SQLException { throw new UnsupportedOperationException(); } public void setCharacterStream( int parameterIndex, Reader reader, int length) throws SQLException { throw new UnsupportedOperationException(); } public void setRef(int parameterIndex, Ref x) throws SQLException { throw new UnsupportedOperationException(); } public void setBlob(int parameterIndex, Blob x) throws SQLException { throw new UnsupportedOperationException(); } public void setClob(int parameterIndex, Clob x) throws SQLException { throw new UnsupportedOperationException(); } public void setArray(int parameterIndex, Array x) throws SQLException { throw new UnsupportedOperationException(); } public CellSetMetaData getMetaData() { return cellSetMetaData; } public void setDate( int parameterIndex, Date x, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public void setTime( int parameterIndex, Time x, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public void setTimestamp( int parameterIndex, Timestamp x, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public void setNull( int parameterIndex, int sqlType, String typeName) throws SQLException { throw new UnsupportedOperationException(); } public void setURL(int parameterIndex, URL x) throws SQLException { throw new UnsupportedOperationException(); } public void setObject( int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } // implement OlapParameterMetaData public String getParameterName(int param) throws OlapException { Parameter paramDef = getParameter(param); return paramDef.getName(); } private Parameter getParameter(int param) throws OlapException { final List parameters = getParameters(); if (param < 1 || param > parameters.size()) { throw getHelper().createException( "parameter ordinal " + param + " out of range"); } return parameters.get(param - 1); } private List getParameters() { // XMLA statements do not have parameters yet return Collections.emptyList(); } public Type getParameterOlapType(int param) throws OlapException { throw Olap4jUtil.needToImplement(this); } public int getParameterCount() { return getParameters().size(); } public int isNullable(int param) throws SQLException { return ParameterMetaData.parameterNullableUnknown; } public boolean isSigned(int param) throws SQLException { final Type type = getParameterOlapType(param); return type instanceof NumericType; } public int getPrecision(int param) throws SQLException { final Type type = getParameterOlapType(param); if (type instanceof NumericType) { return 0; // precision not applicable } if (type instanceof StringType) { return Integer.MAX_VALUE; } return 0; } public int getScale(int param) throws SQLException { return 0; // scale not applicable } public int getParameterType(int param) throws SQLException { final Type type = getParameterOlapType(param); if (type instanceof NumericType) { return Types.NUMERIC; } else if (type instanceof StringType) { return Types.VARCHAR; } else if (type instanceof NullType) { return Types.NULL; } else { return Types.OTHER; } } public String getParameterTypeName(int param) throws SQLException { final Type type = getParameterOlapType(param); return type.toString(); } public String getParameterClassName(int param) throws SQLException { final Type type = getParameterOlapType(param); return foo( new XmlaOlap4jPreparedStatement.TypeHelper>() { public Class booleanType(BooleanType type) { return Boolean.class; } public Class cubeType(CubeType cubeType) { return Cube.class; } public Class decimalType(DecimalType decimalType) { return Number.class; } public Class dimensionType( DimensionType dimensionType) { return Dimension.class; } public Class hierarchyType( HierarchyType hierarchyType) { return Hierarchy.class; } public Class levelType(LevelType levelType) { return Level.class; } public Class memberType(MemberType memberType) { return Member.class; } public Class nullType(NullType nullType) { return Void.class; } public Class numericType(NumericType numericType) { return Number.class; } public Class setType(SetType setType) { return Iterable.class; } public Class stringType(StringType stringType) { return String.class; } public Class tupleType(TupleType tupleType) { return Member[].class; } public Class symbolType(SymbolType symbolType) { // parameters cannot be of this type throw new UnsupportedOperationException(); } }, type).getName(); } public int getParameterMode(int param) throws SQLException { throw Olap4jUtil.needToImplement(this); } // Helper classes private interface TypeHelper { T booleanType(BooleanType type); T cubeType(CubeType cubeType); T decimalType(DecimalType decimalType); T dimensionType(DimensionType dimensionType); T hierarchyType(HierarchyType hierarchyType); T levelType(LevelType levelType); T memberType(MemberType memberType); T nullType(NullType nullType); T numericType(NumericType numericType); T setType(SetType setType); T stringType(StringType stringType); T tupleType(TupleType tupleType); T symbolType(SymbolType symbolType); } T foo(XmlaOlap4jPreparedStatement.TypeHelper helper, Type type) { if (type instanceof BooleanType) { return helper.booleanType((BooleanType) type); } else if (type instanceof CubeType) { return helper.cubeType((CubeType) type); } else if (type instanceof DecimalType) { return helper.decimalType((DecimalType) type); } else if (type instanceof DimensionType) { return helper.dimensionType((DimensionType) type); } else if (type instanceof HierarchyType) { return helper.hierarchyType((HierarchyType) type); } else if (type instanceof LevelType) { return helper.levelType((LevelType) type); } else if (type instanceof MemberType) { return helper.memberType((MemberType) type); } else if (type instanceof NullType) { return helper.nullType((NullType) type); } else if (type instanceof NumericType) { return helper.numericType((NumericType) type); } else if (type instanceof SetType) { return helper.setType((SetType) type); } else if (type instanceof StringType) { return helper.stringType((StringType) type); } else if (type instanceof TupleType) { return helper.tupleType((TupleType) type); } else if (type instanceof SymbolType) { return helper.symbolType((SymbolType) type); } else { throw new UnsupportedOperationException(); } } private interface Parameter { String getName(); void setValue(Object o); void unset(); boolean isSet(); } } // End XmlaOlap4jPreparedStatement.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java0000644000175000017500000014007111707255006024204 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCellSet.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import org.olap4j.impl.Olap4jUtil; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; import java.io.*; import java.math.BigDecimal; import java.net.URL; import java.sql.*; import java.sql.Date; import java.util.*; import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; /** * Implementation of {@link org.olap4j.CellSet} * for XML/A providers. * *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; * it is instantiated using {@link Factory#newCellSet}.

* * @author jhyde * @version $Id: XmlaOlap4jCellSet.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 24, 2007 */ abstract class XmlaOlap4jCellSet implements CellSet { final XmlaOlap4jStatement olap4jStatement; protected boolean closed; private XmlaOlap4jCellSetMetaData metaData; private final Map cellMap = new HashMap(); private final List axisList = new ArrayList(); private final List immutableAxisList = Olap4jUtil.cast(Collections.unmodifiableList(axisList)); private XmlaOlap4jCellSetAxis filterAxis; private static final boolean DEBUG = false; private static final List standardProperties = Arrays.asList( "UName", "Caption", "LName", "LNum", "DisplayInfo"); /** * Creates an XmlaOlap4jCellSet. * * @param olap4jStatement Statement */ XmlaOlap4jCellSet( XmlaOlap4jStatement olap4jStatement) { assert olap4jStatement != null; this.olap4jStatement = olap4jStatement; this.closed = false; } /** * Returns the error-handler. * * @return Error handler */ private XmlaHelper getHelper() { return olap4jStatement.olap4jConnection.helper; } /** * Gets response from the XMLA request and populates cell set axes and cells * with it. * * @throws OlapException on error */ void populate() throws OlapException { byte[] bytes = olap4jStatement.getBytes(); Document doc; try { doc = parse(bytes); } catch (IOException e) { throw getHelper().createException( "error creating CellSet", e); } catch (SAXException e) { throw getHelper().createException( "error creating CellSet", e); } // // // // // // // (see below) // // // // // final Element envelope = doc.getDocumentElement(); if (DEBUG) { System.out.println(XmlaOlap4jUtil.toString(doc, true)); } assert envelope.getLocalName().equals("Envelope"); assert envelope.getNamespaceURI().equals(SOAP_NS); Element body = findChild(envelope, SOAP_NS, "Body"); Element fault = findChild(body, SOAP_NS, "Fault"); if (fault != null) { /* SOAP-ENV:Client.00HSBC01 XMLA connection datasource not found Mondrian 00HSBC01 The Mondrian XML: Mondrian Error:Internal error: no catalog named 'LOCALDB' */ // TODO: log doc to logfile throw getHelper().createException( "XMLA provider gave exception: " + XmlaOlap4jUtil.prettyPrint(fault)); } Element executeResponse = findChild(body, XMLA_NS, "ExecuteResponse"); Element returnElement = findChild(executeResponse, XMLA_NS, "return"); // has children // // // // // FOO // // // // ... // // // // // // // ... // // // // ... // final Element root = findChild(returnElement, MDDATASET_NS, "root"); if (olap4jStatement instanceof XmlaOlap4jPreparedStatement) { this.metaData = ((XmlaOlap4jPreparedStatement) olap4jStatement) .cellSetMetaData; } else { this.metaData = createMetaData(root); } // todo: use CellInfo element to determine mapping of cell properties // to XML tags /* */ final Element axesNode = findChild(root, MDDATASET_NS, "Axes"); // First pass, gather up a list of member unique names to fetch // all at once. // // NOTE: This approach allows the driver to fetch a large number // of members in one round trip, which is much more efficient. // However, if the axis has a very large number of members, the map // may use too much memory. This is an unresolved issue. final MetadataReader metadataReader = metaData.cube.getMetadataReader(); final Map memberMap = new HashMap(); List uniqueNames = new ArrayList(); for (Element axisNode : findChildren(axesNode, MDDATASET_NS, "Axis")) { final Element tuplesNode = findChild(axisNode, MDDATASET_NS, "Tuples"); for (Element tupleNode : findChildren(tuplesNode, MDDATASET_NS, "Tuple")) { for (Element memberNode : findChildren(tupleNode, MDDATASET_NS, "Member")) { final String uname = stringElement(memberNode, "UName"); uniqueNames.add(uname); } } } // Fetch all members on all axes. Hopefully it can all be done in one // round trip, or they are in cache already. metadataReader.lookupMembersByUniqueName(uniqueNames, memberMap); // Second pass, populate the axis. final Map propertyValues = new HashMap(); for (Element axisNode : findChildren(axesNode, MDDATASET_NS, "Axis")) { final String axisName = axisNode.getAttribute("name"); final Axis axis = lookupAxis(axisName); final ArrayList positions = new ArrayList(); final XmlaOlap4jCellSetAxis cellSetAxis = new XmlaOlap4jCellSetAxis( this, axis, Collections.unmodifiableList(positions)); if (axis.isFilter()) { filterAxis = cellSetAxis; } else { axisList.add(cellSetAxis); } final Element tuplesNode = findChild(axisNode, MDDATASET_NS, "Tuples"); for (Element tupleNode : findChildren(tuplesNode, MDDATASET_NS, "Tuple")) { final List members = new ArrayList(); for (Element memberNode : findChildren(tupleNode, MDDATASET_NS, "Member")) { String hierarchyName = memberNode.getAttribute("Hierarchy"); final String uname = stringElement(memberNode, "UName"); XmlaOlap4jMemberBase member = memberMap.get(uname); if (member == null) { final String caption = stringElement(memberNode, "Caption"); final int lnum = integerElement(memberNode, "LNum"); final Hierarchy hierarchy = lookupHierarchy(metaData.cube, hierarchyName); final Level level = hierarchy.getLevels().get(lnum); member = new XmlaOlap4jSurpriseMember( this, level, hierarchy, lnum, caption, uname); } propertyValues.clear(); for (Element childNode : childElements(memberNode)) { XmlaOlap4jCellSetMemberProperty property = ((XmlaOlap4jCellSetAxisMetaData) cellSetAxis.getAxisMetaData()).lookupProperty( hierarchyName, childNode.getLocalName()); if (property != null) { String value = childNode.getTextContent(); propertyValues.put(property, value); } } if (!propertyValues.isEmpty()) { member = new XmlaOlap4jPositionMember( member, propertyValues); } members.add(member); } positions.add( new XmlaOlap4jPosition( members, positions.size())); } } // If XMLA did not return a filter axis, it means that the WHERE clause // evaluated to zero tuples. (If the query had no WHERE clause, it // would have evaluated to a single tuple with zero positions.) if (filterAxis == null) { filterAxis = new XmlaOlap4jCellSetAxis( this, Axis.FILTER, Collections.emptyList()); } final Element cellDataNode = findChild(root, MDDATASET_NS, "CellData"); for (Element cell : findChildren(cellDataNode, MDDATASET_NS, "Cell")) { propertyValues.clear(); final int cellOrdinal = Integer.valueOf(cell.getAttribute("CellOrdinal")); final Object value = getTypedValue(cell); final String formattedValue = stringElement(cell, "FmtValue"); final String formatString = stringElement(cell, "FormatString"); Olap4jUtil.discard(formatString); for (Element element : childElements(cell)) { String tag = element.getLocalName(); final Property property = metaData.propertiesByTag.get(tag); if (property != null) { propertyValues.put(property, element.getTextContent()); } } cellMap.put( cellOrdinal, new XmlaOlap4jCell( this, cellOrdinal, value, formattedValue, propertyValues)); } } /** * Returns the value of a cell, cast to the appropriate Java object type * corresponding to the XML schema (XSD) type of the value. * *

The value type must conform to XSD definitions of the XML element. See * RELAX * NG, Chapter 19 for a full list of possible data types. * *

This method does not currently support all types; must numeric types * are supported, but no dates are yet supported. Those not supported * fall back to Strings. * * @param cell The cell of which we want the casted object. * @return The object with a correct value. * @throws OlapException if any error is encountered while casting the cell * value */ private Object getTypedValue(Element cell) throws OlapException { 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"); try { if (type.equals("xsd:int")) { return XmlaOlap4jUtil.intElement(cell, "Value"); } else if (type.equals("xsd:integer")) { return XmlaOlap4jUtil.integerElement(cell, "Value"); } else if (type.equals("xsd:double")) { return XmlaOlap4jUtil.doubleElement(cell, "Value"); } else if (type.equals("xsd:float")) { return XmlaOlap4jUtil.floatElement(cell, "Value"); } else if (type.equals("xsd:long")) { return XmlaOlap4jUtil.longElement(cell, "Value"); } else if (type.equals("xsd:boolean")) { return XmlaOlap4jUtil.booleanElement(cell, "Value"); } else { return XmlaOlap4jUtil.stringElement(cell, "Value"); } } catch (Exception e) { throw getHelper().createException( "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. * * @param root Root node of XMLA result * @return Metadata describing this cell set * @throws OlapException on error */ private XmlaOlap4jCellSetMetaData createMetaData(Element root) throws OlapException { final Element olapInfo = findChild(root, MDDATASET_NS, "OlapInfo"); final Element cubeInfo = findChild(olapInfo, MDDATASET_NS, "CubeInfo"); final Element cubeNode = findChild(cubeInfo, MDDATASET_NS, "Cube"); final Element cubeNameNode = findChild(cubeNode, MDDATASET_NS, "CubeName"); final String cubeName = gatherText(cubeNameNode); XmlaOlap4jCube cube = lookupCube( olap4jStatement.olap4jConnection.olap4jDatabaseMetaData, cubeName); if (cube == null) { throw getHelper().createException( "Internal error: cube '" + cubeName + "' not found"); } final Element axesInfo = findChild(olapInfo, MDDATASET_NS, "AxesInfo"); final List axisInfos = findChildren(axesInfo, MDDATASET_NS, "AxisInfo"); final List axisMetaDataList = new ArrayList(); XmlaOlap4jCellSetAxisMetaData filterAxisMetaData = null; for (Element axisInfo : axisInfos) { final String axisName = axisInfo.getAttribute("name"); Axis axis = lookupAxis(axisName); final List hierarchyInfos = findChildren(axisInfo, MDDATASET_NS, "HierarchyInfo"); final List hierarchyList = new ArrayList(); /* ... */ final List propertyList = new ArrayList(); for (Element hierarchyInfo : hierarchyInfos) { final String hierarchyName = hierarchyInfo.getAttribute("name"); Hierarchy hierarchy = lookupHierarchy(cube, hierarchyName); hierarchyList.add(hierarchy); for (Element childNode : childElements(hierarchyInfo)) { String tag = childNode.getLocalName(); if (standardProperties.contains(tag)) { continue; } final String propertyUniqueName = childNode.getAttribute("name"); final XmlaOlap4jCellSetMemberProperty property = new XmlaOlap4jCellSetMemberProperty( propertyUniqueName, hierarchy, tag); propertyList.add(property); } } final XmlaOlap4jCellSetAxisMetaData axisMetaData = new XmlaOlap4jCellSetAxisMetaData( olap4jStatement.olap4jConnection, axis, hierarchyList, propertyList); if (axis.isFilter()) { filterAxisMetaData = axisMetaData; } else { axisMetaDataList.add(axisMetaData); } } if (filterAxisMetaData == null) { filterAxisMetaData = new XmlaOlap4jCellSetAxisMetaData( olap4jStatement.olap4jConnection, Axis.FILTER, Collections.emptyList(), Collections.emptyList()); } final Element cellInfo = findChild(olapInfo, MDDATASET_NS, "CellInfo"); List cellProperties = new ArrayList(); for (Element element : childElements(cellInfo)) { cellProperties.add( new XmlaOlap4jCellProperty( element.getLocalName(), element.getAttribute("name"))); } return new XmlaOlap4jCellSetMetaData( olap4jStatement, cube, filterAxisMetaData, axisMetaDataList, cellProperties); } /** * Looks up a cube with a given name within the current database, * catalog and schema bound to the source connection. * *

If there are several with the same name, returns the first. * * @param databaseMetaData Database metadata * @param cubeName Cube name * @return Cube, or null if not found * @throws OlapException on error */ private XmlaOlap4jCube lookupCube( XmlaOlap4jDatabaseMetaData databaseMetaData, String cubeName) throws OlapException { for (Cube cube : databaseMetaData.olap4jConnection.getOlapSchema().getCubes()) { if (cubeName.equals(cube.getName())) { return (XmlaOlap4jCube) cube; } if (cubeName.equals("[" + cube.getName() + "]")) { return (XmlaOlap4jCube) cube; } } return null; } /** * Looks up a hierarchy in a cube with a given name or, failing that, a * given unique name. Throws if not found. * * @param cube Cube * @param hierarchyName Name (or unique name) of hierarchy. * @return Hierarchy * @throws OlapException on error */ private Hierarchy lookupHierarchy(XmlaOlap4jCube cube, String hierarchyName) throws OlapException { Hierarchy hierarchy = cube.getHierarchies().get(hierarchyName); if (hierarchy == null) { for (Hierarchy hierarchy1 : cube.getHierarchies()) { if (hierarchy1.getUniqueName().equals(hierarchyName)) { hierarchy = hierarchy1; break; } } if (hierarchy == null) { throw getHelper().createException( "Internal error: hierarchy '" + hierarchyName + "' not found in cube '" + cube.getName() + "'"); } } return hierarchy; } /** * Looks up an Axis with a given name. * * @param axisName Name of axis * @return Axis */ private Axis lookupAxis(String axisName) { if (axisName.startsWith("Axis")) { final Integer ordinal = Integer.valueOf(axisName.substring("Axis".length())); return Axis.Factory.forOrdinal(ordinal); } else { return Axis.FILTER; } } public CellSetMetaData getMetaData() { return metaData; } public Cell getCell(List coordinates) { return getCellInternal(coordinatesToOrdinal(coordinates)); } public Cell getCell(int ordinal) { return getCellInternal(ordinal); } public Cell getCell(Position... positions) { if (positions.length != getAxes().size()) { throw new IllegalArgumentException( "cell coordinates should have dimension " + getAxes().size()); } List coords = new ArrayList(positions.length); for (Position position : positions) { coords.add(position.getOrdinal()); } return getCell(coords); } /** * Returns a cell given its ordinal. * * @param pos Ordinal * @return Cell * @throws IndexOutOfBoundsException if ordinal is not in range */ private Cell getCellInternal(int pos) { final Cell cell = cellMap.get(pos); if (cell == null) { if (pos < 0 || pos >= maxOrdinal()) { throw new IndexOutOfBoundsException(); } else { // Cell is within bounds, but is not held in the cache because // it has no value. Manufacture a cell with an empty value. return new XmlaOlap4jCell( this, pos, null, "", Collections.emptyMap()); } } return cell; } /** * Returns a string describing the maximum coordinates of this cell set; * for example "2, 3" for a cell set with 2 columns and 3 rows. * * @return description of cell set bounds */ private String getBoundsAsString() { StringBuilder buf = new StringBuilder(); int k = 0; for (CellSetAxis axis : getAxes()) { if (k++ > 0) { buf.append(", "); } buf.append(axis.getPositionCount()); } return buf.toString(); } public List getAxes() { return immutableAxisList; } public CellSetAxis getFilterAxis() { return filterAxis; } /** * Returns the ordinal of the last cell in this cell set. This is the * product of the cardinalities of all axes. * * @return ordinal of last cell in cell set */ private int maxOrdinal() { int modulo = 1; for (CellSetAxis axis : axisList) { modulo *= axis.getPositionCount(); } return modulo; } public List ordinalToCoordinates(int ordinal) { List axes = getAxes(); final List list = new ArrayList(axes.size()); int modulo = 1; for (CellSetAxis axis : axes) { int prevModulo = modulo; modulo *= axis.getPositionCount(); list.add((ordinal % modulo) / prevModulo); } if (ordinal < 0 || ordinal >= modulo) { throw new IndexOutOfBoundsException( "Cell ordinal " + ordinal + ") lies outside CellSet bounds (" + getBoundsAsString() + ")"); } return list; } public int coordinatesToOrdinal(List coordinates) { List axes = getAxes(); if (coordinates.size() != axes.size()) { throw new IllegalArgumentException( "Coordinates have different dimension " + coordinates.size() + " than axes " + axes.size()); } int modulo = 1; int ordinal = 0; int k = 0; for (CellSetAxis axis : axes) { final Integer coordinate = coordinates.get(k++); if (coordinate < 0 || coordinate >= axis.getPositionCount()) { throw new IndexOutOfBoundsException( "Coordinate " + coordinate + " of axis " + k + " is out of range (" + getBoundsAsString() + ")"); } ordinal += coordinate * modulo; modulo *= axis.getPositionCount(); } return ordinal; } public boolean next() throws SQLException { throw new UnsupportedOperationException(); } public void close() throws SQLException { this.closed = true; } public boolean wasNull() throws SQLException { throw new UnsupportedOperationException(); } public String getString(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public boolean getBoolean(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public byte getByte(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public short getShort(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public int getInt(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public long getLong(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public float getFloat(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public double getDouble(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal( int columnIndex, int scale) throws SQLException { throw new UnsupportedOperationException(); } public byte[] getBytes(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getAsciiStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getUnicodeStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getBinaryStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public String getString(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public boolean getBoolean(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public byte getByte(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public short getShort(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public int getInt(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public long getLong(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public float getFloat(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public double getDouble(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal( String columnLabel, int scale) throws SQLException { throw new UnsupportedOperationException(); } public byte[] getBytes(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getAsciiStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getUnicodeStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getBinaryStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public SQLWarning getWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void clearWarnings() throws SQLException { throw new UnsupportedOperationException(); } public String getCursorName() throws SQLException { throw new UnsupportedOperationException(); } public Object getObject(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Object getObject(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public int findColumn(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Reader getCharacterStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Reader getCharacterStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public boolean isBeforeFirst() throws SQLException { throw new UnsupportedOperationException(); } public boolean isAfterLast() throws SQLException { throw new UnsupportedOperationException(); } public boolean isFirst() throws SQLException { throw new UnsupportedOperationException(); } public boolean isLast() throws SQLException { throw new UnsupportedOperationException(); } public void beforeFirst() throws SQLException { throw new UnsupportedOperationException(); } public void afterLast() throws SQLException { throw new UnsupportedOperationException(); } public boolean first() throws SQLException { throw new UnsupportedOperationException(); } public boolean last() throws SQLException { throw new UnsupportedOperationException(); } public int getRow() throws SQLException { throw new UnsupportedOperationException(); } public boolean absolute(int row) throws SQLException { throw new UnsupportedOperationException(); } public boolean relative(int rows) throws SQLException { throw new UnsupportedOperationException(); } public boolean previous() throws SQLException { throw new UnsupportedOperationException(); } public void setFetchDirection(int direction) throws SQLException { throw new UnsupportedOperationException(); } public int getFetchDirection() throws SQLException { throw new UnsupportedOperationException(); } public void setFetchSize(int rows) throws SQLException { throw new UnsupportedOperationException(); } public int getFetchSize() throws SQLException { throw new UnsupportedOperationException(); } public int getType() throws SQLException { throw new UnsupportedOperationException(); } public int getConcurrency() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowUpdated() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowInserted() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowDeleted() throws SQLException { throw new UnsupportedOperationException(); } public void updateNull(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public void updateBoolean(int columnIndex, boolean x) throws SQLException { throw new UnsupportedOperationException(); } public void updateByte(int columnIndex, byte x) throws SQLException { throw new UnsupportedOperationException(); } public void updateShort(int columnIndex, short x) throws SQLException { throw new UnsupportedOperationException(); } public void updateInt(int columnIndex, int x) throws SQLException { throw new UnsupportedOperationException(); } public void updateLong(int columnIndex, long x) throws SQLException { throw new UnsupportedOperationException(); } public void updateFloat(int columnIndex, float x) throws SQLException { throw new UnsupportedOperationException(); } public void updateDouble(int columnIndex, double x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBigDecimal( int columnIndex, BigDecimal x) throws SQLException { throw new UnsupportedOperationException(); } public void updateString(int columnIndex, String x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBytes(int columnIndex, byte x[]) throws SQLException { throw new UnsupportedOperationException(); } public void updateDate(int columnIndex, Date x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTime(int columnIndex, Time x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTimestamp( int columnIndex, Timestamp x) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( int columnIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( int columnIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( int columnIndex, Reader x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject( int columnIndex, Object x, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(int columnIndex, Object x) throws SQLException { throw new UnsupportedOperationException(); } public void updateNull(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateBoolean( String columnLabel, boolean x) throws SQLException { throw new UnsupportedOperationException(); } public void updateByte(String columnLabel, byte x) throws SQLException { throw new UnsupportedOperationException(); } public void updateShort(String columnLabel, short x) throws SQLException { throw new UnsupportedOperationException(); } public void updateInt(String columnLabel, int x) throws SQLException { throw new UnsupportedOperationException(); } public void updateLong(String columnLabel, long x) throws SQLException { throw new UnsupportedOperationException(); } public void updateFloat(String columnLabel, float x) throws SQLException { throw new UnsupportedOperationException(); } public void updateDouble(String columnLabel, double x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBigDecimal( String columnLabel, BigDecimal x) throws SQLException { throw new UnsupportedOperationException(); } public void updateString(String columnLabel, String x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBytes(String columnLabel, byte x[]) throws SQLException { throw new UnsupportedOperationException(); } public void updateDate(String columnLabel, Date x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTime(String columnLabel, Time x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTimestamp( String columnLabel, Timestamp x) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( String columnLabel, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( String columnLabel, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( String columnLabel, Reader reader, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject( String columnLabel, Object x, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(String columnLabel, Object x) throws SQLException { throw new UnsupportedOperationException(); } public void insertRow() throws SQLException { throw new UnsupportedOperationException(); } public void updateRow() throws SQLException { throw new UnsupportedOperationException(); } public void deleteRow() throws SQLException { throw new UnsupportedOperationException(); } public void refreshRow() throws SQLException { throw new UnsupportedOperationException(); } public void cancelRowUpdates() throws SQLException { throw new UnsupportedOperationException(); } public void moveToInsertRow() throws SQLException { throw new UnsupportedOperationException(); } public void moveToCurrentRow() throws SQLException { throw new UnsupportedOperationException(); } public OlapStatement getStatement() { return olap4jStatement; } public Object getObject( int columnIndex, Map> map) throws SQLException { throw new UnsupportedOperationException(); } public Ref getRef(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Blob getBlob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Clob getClob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Array getArray(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Object getObject( String columnLabel, Map> map) throws SQLException { throw new UnsupportedOperationException(); } public Ref getRef(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Blob getBlob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Clob getClob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Array getArray(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(int columnIndex, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(int columnIndex, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp( int columnIndex, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp( String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public URL getURL(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public URL getURL(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateRef(int columnIndex, Ref x) throws SQLException { throw new UnsupportedOperationException(); } public void updateRef(String columnLabel, Ref x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(int columnIndex, Blob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(String columnLabel, Blob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(int columnIndex, Clob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(String columnLabel, Clob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateArray(int columnIndex, Array x) throws SQLException { throw new UnsupportedOperationException(); } public void updateArray(String columnLabel, Array x) throws SQLException { throw new UnsupportedOperationException(); } // implement Wrapper public T unwrap(Class iface) throws SQLException { throw new UnsupportedOperationException(); } public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException(); } /** * Implementation of {@link Member} for a member which is not present * in the cube (probably because the member is a calculated member * defined in the query). */ private static class XmlaOlap4jSurpriseMember implements XmlaOlap4jMemberBase { private final XmlaOlap4jCellSet cellSet; private final Level level; private final Hierarchy hierarchy; private final int lnum; private final String caption; private final String uname; /** * Creates an XmlaOlap4jSurpriseMember. * * @param cellSet Cell set * @param level Level * @param hierarchy Hierarchy * @param lnum Level number * @param caption Caption * @param uname Member unique name */ XmlaOlap4jSurpriseMember( XmlaOlap4jCellSet cellSet, Level level, Hierarchy hierarchy, int lnum, String caption, String uname) { this.cellSet = cellSet; this.level = level; this.hierarchy = hierarchy; this.lnum = lnum; this.caption = caption; this.uname = uname; } public final XmlaOlap4jCube getCube() { return cellSet.metaData.cube; } public final XmlaOlap4jConnection getConnection() { return getCatalog().olap4jDatabaseMetaData.olap4jConnection; } public final XmlaOlap4jCatalog getCatalog() { return getCube().olap4jSchema.olap4jCatalog; } public Map getPropertyValueMap() { return Collections.emptyMap(); } public NamedList getChildMembers() { return Olap4jUtil.emptyNamedList(); } public int getChildMemberCount() { return 0; } public Member getParentMember() { return null; } public Level getLevel() { return level; } public Hierarchy getHierarchy() { return hierarchy; } public Dimension getDimension() { return hierarchy.getDimension(); } public Type getMemberType() { return Type.UNKNOWN; } public boolean isAll() { return false; // FIXME } public boolean isChildOrEqualTo(Member member) { return false; // FIXME } public boolean isCalculated() { return false; // FIXME } public int getSolveOrder() { return 0; // FIXME } public ParseTreeNode getExpression() { return null; } public List getAncestorMembers() { return Collections.emptyList(); // FIXME } public boolean isCalculatedInQuery() { return true; // probably } public Object getPropertyValue(Property property) { return null; } public String getPropertyFormattedValue(Property property) { return null; } public void setProperty(Property property, Object value) { throw new UnsupportedOperationException(); } public NamedList getProperties() { return Olap4jUtil.emptyNamedList(); } public int getOrdinal() { return -1; // FIXME } public boolean isHidden() { return false; } public int getDepth() { return lnum; } public Member getDataMember() { return null; } public String getName() { return caption; } public String getUniqueName() { return uname; } public String getCaption() { return caption; } public String getDescription() { return null; } public boolean isVisible() { return true; } } } // End XmlaOlap4jCellSet.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/FactoryJdbc3Impl.java0000644000175000017500000001133111707255004024046 0ustar drazzibdrazzib/* // $Id: FactoryJdbc3Impl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import java.sql.*; import java.util.*; /** * Implementation of {@link Factory} for JDBC 3.0. * * @author jhyde * @version $Id: FactoryJdbc3Impl.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 14, 2007 */ class FactoryJdbc3Impl implements Factory { /** * Creates a FactoryJdbc3Impl. */ public FactoryJdbc3Impl() { } public Connection newConnection( XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { return new FactoryJdbc3Impl.XmlaOlap4jConnectionJdbc3( driver, proxy, url, info); } public EmptyResultSet newEmptyResultSet( XmlaOlap4jConnection olap4jConnection) { List headerList = Collections.emptyList(); List> rowList = Collections.emptyList(); return new FactoryJdbc3Impl.EmptyResultSetJdbc3( olap4jConnection, headerList, rowList); } public ResultSet newFixedResultSet( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { return new EmptyResultSetJdbc3(olap4jConnection, headerList, rowList); } public XmlaOlap4jCellSet newCellSet( XmlaOlap4jStatement olap4jStatement) throws OlapException { return new XmlaOlap4jCellSetJdbc3(olap4jStatement); } public XmlaOlap4jStatement newStatement( XmlaOlap4jConnection olap4jConnection) { return new XmlaOlap4jStatementJdbc3(olap4jConnection); } public XmlaOlap4jPreparedStatement newPreparedStatement( String mdx, XmlaOlap4jConnection olap4jConnection) throws OlapException { return new XmlaOlap4jPreparedStatementJdbc3( olap4jConnection, mdx); } public XmlaOlap4jDatabaseMetaData newDatabaseMetaData( XmlaOlap4jConnection olap4jConnection) { return new XmlaOlap4jDatabaseMetaDataJdbc3( olap4jConnection); } // Inner classes private static class XmlaOlap4jStatementJdbc3 extends XmlaOlap4jStatement { public XmlaOlap4jStatementJdbc3( XmlaOlap4jConnection olap4jConnection) { super(olap4jConnection); } } private static class XmlaOlap4jPreparedStatementJdbc3 extends XmlaOlap4jPreparedStatement { public XmlaOlap4jPreparedStatementJdbc3( XmlaOlap4jConnection olap4jConnection, String mdx) throws OlapException { super(olap4jConnection, mdx); } } private static class XmlaOlap4jCellSetJdbc3 extends XmlaOlap4jCellSet { public XmlaOlap4jCellSetJdbc3( XmlaOlap4jStatement olap4jStatement) throws OlapException { super(olap4jStatement); } } private static class EmptyResultSetJdbc3 extends EmptyResultSet { public EmptyResultSetJdbc3( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { super(olap4jConnection, headerList, rowList); } } private class XmlaOlap4jConnectionJdbc3 extends XmlaOlap4jConnection { public XmlaOlap4jConnectionJdbc3( XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { super(FactoryJdbc3Impl.this, driver, proxy, url, info); } } private static class XmlaOlap4jDatabaseMetaDataJdbc3 extends XmlaOlap4jDatabaseMetaData { public XmlaOlap4jDatabaseMetaDataJdbc3( XmlaOlap4jConnection olap4jConnection) { super(olap4jConnection); } } } // End FactoryJdbc3Impl.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java0000644000175000017500000003230211711466574024623 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jStatement.java 496 2012-01-30 13:33:27Z pstoellberger $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import org.olap4j.mdx.*; import java.io.StringWriter; import java.sql.*; import java.util.concurrent.*; /** * Implementation of {@link org.olap4j.OlapStatement} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jStatement.java 496 2012-01-30 13:33:27Z pstoellberger $ * @since May 24, 2007 */ abstract class XmlaOlap4jStatement implements OlapStatement { final XmlaOlap4jConnection olap4jConnection; private boolean closed; /** * Current cell set, or null if the statement is not executing anything. * Any method which modifies this member must synchronize * on the {@link XmlaOlap4jStatement}. */ XmlaOlap4jCellSet openCellSet; private boolean canceled; int timeoutSeconds; Future future; /** * Creates an XmlaOlap4jStatement. * * @param olap4jConnection Connection */ XmlaOlap4jStatement( XmlaOlap4jConnection olap4jConnection) { assert olap4jConnection != null; this.olap4jConnection = olap4jConnection; this.closed = false; } /** * Returns the error-handler. * * @return Error handler */ private XmlaHelper getHelper() { return olap4jConnection.helper; } // implement Statement public ResultSet executeQuery(String sql) throws SQLException { throw new UnsupportedOperationException(); } private void checkOpen() throws SQLException { if (closed) { throw getHelper().createException("closed"); } } public int executeUpdate(String sql) throws SQLException { throw new UnsupportedOperationException(); } public void close() throws SQLException { if (!closed) { closed = true; if (openCellSet != null) { CellSet c = openCellSet; openCellSet = null; c.close(); } } } public int getMaxFieldSize() throws SQLException { throw new UnsupportedOperationException(); } public void setMaxFieldSize(int max) throws SQLException { throw new UnsupportedOperationException(); } public int getMaxRows() throws SQLException { throw new UnsupportedOperationException(); } public void setMaxRows(int max) throws SQLException { throw new UnsupportedOperationException(); } public void setEscapeProcessing(boolean enable) throws SQLException { throw new UnsupportedOperationException(); } public int getQueryTimeout() throws SQLException { return timeoutSeconds; } public void setQueryTimeout(int seconds) throws SQLException { if (seconds < 0) { throw getHelper().createException( "illegal timeout value " + seconds); } this.timeoutSeconds = seconds; } public synchronized void cancel() { if (!canceled) { canceled = true; if (future != null) { future.cancel(true); } } } public SQLWarning getWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void clearWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void setCursorName(String name) throws SQLException { throw new UnsupportedOperationException(); } public boolean execute(String sql) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getResultSet() throws SQLException { throw new UnsupportedOperationException(); } public int getUpdateCount() throws SQLException { throw new UnsupportedOperationException(); } public boolean getMoreResults() throws SQLException { throw new UnsupportedOperationException(); } public void setFetchDirection(int direction) throws SQLException { throw new UnsupportedOperationException(); } public int getFetchDirection() throws SQLException { throw new UnsupportedOperationException(); } public void setFetchSize(int rows) throws SQLException { throw new UnsupportedOperationException(); } public int getFetchSize() throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetConcurrency() throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetType() throws SQLException { throw new UnsupportedOperationException(); } public void addBatch(String sql) throws SQLException { throw new UnsupportedOperationException(); } public void clearBatch() throws SQLException { throw new UnsupportedOperationException(); } public int[] executeBatch() throws SQLException { throw new UnsupportedOperationException(); } public OlapConnection getConnection() { return olap4jConnection; } public boolean getMoreResults(int current) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getGeneratedKeys() throws SQLException { throw new UnsupportedOperationException(); } public int executeUpdate( String sql, int autoGeneratedKeys) throws SQLException { throw new UnsupportedOperationException(); } public int executeUpdate( String sql, int columnIndexes[]) throws SQLException { throw new UnsupportedOperationException(); } public int executeUpdate( String sql, String columnNames[]) throws SQLException { throw new UnsupportedOperationException(); } public boolean execute( String sql, int autoGeneratedKeys) throws SQLException { throw new UnsupportedOperationException(); } public boolean execute( String sql, int columnIndexes[]) throws SQLException { throw new UnsupportedOperationException(); } public boolean execute( String sql, String columnNames[]) throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetHoldability() throws SQLException { throw new UnsupportedOperationException(); } public boolean isClosed() throws SQLException { return closed; } public void setPoolable(boolean poolable) throws SQLException { throw new UnsupportedOperationException(); } public boolean isPoolable() throws SQLException { throw new UnsupportedOperationException(); } // implement Wrapper public T unwrap(Class iface) throws SQLException { if (iface.isInstance(this)) { return iface.cast(this); } throw getHelper().createException( "does not implement '" + iface + "'"); } public boolean isWrapperFor(Class iface) throws SQLException { return iface.isInstance(this); } // implement OlapStatement public CellSet executeOlapQuery(String mdx) throws OlapException { final String catalog = olap4jConnection.getCatalog(); final String dataSourceInfo = olap4jConnection.getDatabase(); final String roleName = olap4jConnection.getRoleName(); final String propList = olap4jConnection.makeConnectionPropertyList(); StringBuilder buf = new StringBuilder( "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n"); if (catalog != null) { buf.append(" "); buf.append(catalog); buf.append("\n"); } if (propList != null) { buf.append(propList); } if (roleName != null && !("".equals(roleName))) { buf.append(" "); buf.append(roleName); buf.append("\n"); } if (dataSourceInfo != null) { buf.append(" "); buf.append(dataSourceInfo); buf.append("\n"); } buf.append( " Multidimensional\n" + " TupleFormat\n" + " \n" + " \n" + "\n" + "\n" + ""); final String request = buf.toString(); // Close the previous open CellSet, if there is one. synchronized (this) { if (openCellSet != null) { final XmlaOlap4jCellSet cs = openCellSet; openCellSet = null; try { cs.close(); } catch (SQLException e) { throw getHelper().createException( "Error while closing previous CellSet", e); } } this.future = olap4jConnection.proxy.submit( olap4jConnection.serverInfos, request); openCellSet = olap4jConnection.factory.newCellSet(this); } // Release the monitor before calling populate, so that cancel can // grab the monitor if it needs to. openCellSet.populate(); return openCellSet; } public CellSet executeOlapQuery( SelectNode selectNode) throws OlapException { final String mdx = toString(selectNode); return executeOlapQuery(mdx); } public void addListener( CellSetListener.Granularity granularity, CellSetListener listener) throws OlapException { throw getHelper().createException( "This driver does not support the cell listener API."); } /** * Waits for an XMLA request to complete. * *

You must not hold the monitor on this Statement when calling this * method; otherwise {@link #cancel()} will not be able to operate. * * @return Byte array resulting from successful request * * @throws OlapException if error occurred, or request timed out or * was canceled */ byte[] getBytes() throws OlapException { synchronized (this) { if (future == null) { throw new IllegalArgumentException(); } } try { // Wait for the request to complete, with timeout if necessary. // Whether or not timeout is used, the request can still be // canceled. if (timeoutSeconds > 0) { return future.get(timeoutSeconds, TimeUnit.SECONDS); } else { return future.get(); } } catch (InterruptedException e) { throw getHelper().createException(null, e); } catch (ExecutionException e) { throw getHelper().createException(null, e.getCause()); } catch (TimeoutException e) { throw getHelper().createException( "Query timeout of " + timeoutSeconds + " seconds exceeded"); } catch (CancellationException e) { throw getHelper().createException("Query canceled"); } finally { synchronized (this) { if (future == null) { throw new IllegalArgumentException(); } future = null; } } } /** * Converts a {@link org.olap4j.mdx.ParseTreeNode} to MDX string. * * @param node Parse tree node * @return MDX text */ private static String toString(ParseTreeNode node) { StringWriter sw = new StringWriter(); ParseTreeWriter parseTreeWriter = new ParseTreeWriter(sw); node.unparse(parseTreeWriter); return sw.toString(); } } // End XmlaOlap4jStatement.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jServerInfos.java0000644000175000017500000000326111707255006025115 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jServerInfos.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import java.net.URL; /** * Common set of functions for an XMLA URL Provider. * @version $Id: XmlaOlap4jServerInfos.java 483 2012-01-05 23:43:18Z jhyde $ */ public interface XmlaOlap4jServerInfos { /** * Returns the URL to use. * @return the url. */ URL getUrl(); /** * Returns the username to use with the URL. * @return the username. */ String getUsername(); /** * Returns the password to use with the URL. * @return the password. */ String getPassword(); /** * Returns a unique sesison ID to use. * @return the session id. */ String getSessionId(); /** * Stores the session id on the server. * @param sessionId The session id to use. */ void setSessionId(String sessionId); } // End XmlaOlap4jServerInfos.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/FactoryJdbc4Impl.java0000644000175000017500000001357111707255006024061 0ustar drazzibdrazzib/* // $Id: FactoryJdbc4Impl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import java.sql.*; import java.util.*; /** * Implementation of {@link Factory} for JDBC 4.0. * * @author jhyde * @version $Id: FactoryJdbc4Impl.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 14, 2007 */ class FactoryJdbc4Impl implements Factory { /** * Creates a FactoryJdbc4Impl. */ public FactoryJdbc4Impl() { } public Connection newConnection( XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { return new XmlaOlap4jConnectionJdbc4( this, driver, proxy, url, info); } public EmptyResultSet newEmptyResultSet( XmlaOlap4jConnection olap4jConnection) { List headerList = Collections.emptyList(); List> rowList = Collections.emptyList(); return new EmptyResultSetJdbc4(olap4jConnection, headerList, rowList); } public ResultSet newFixedResultSet( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { return new EmptyResultSetJdbc4( olap4jConnection, headerList, rowList); } public XmlaOlap4jCellSet newCellSet( XmlaOlap4jStatement olap4jStatement) throws OlapException { return new XmlaOlap4jCellSetJdbc4(olap4jStatement); } public XmlaOlap4jStatement newStatement( XmlaOlap4jConnection olap4jConnection) { return new XmlaOlap4jStatementJdbc4(olap4jConnection); } public XmlaOlap4jPreparedStatement newPreparedStatement( String mdx, XmlaOlap4jConnection olap4jConnection) throws OlapException { return new XmlaOlap4jPreparedStatementJdbc4(olap4jConnection, mdx); } public XmlaOlap4jDatabaseMetaData newDatabaseMetaData( XmlaOlap4jConnection olap4jConnection) { return new XmlaOlap4jDatabaseMetaDataJdbc4(olap4jConnection); } // Inner classes private static class EmptyResultSetJdbc4 extends FactoryJdbc4Plus.AbstractEmptyResultSet { /** * Creates a EmptyResultSetJdbc4. * * @param olap4jConnection Connection * @param headerList Column names * @param rowList List of row values */ EmptyResultSetJdbc4( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { super(olap4jConnection, headerList, rowList); } } private static class XmlaOlap4jConnectionJdbc4 extends FactoryJdbc4Plus.AbstractConnection { /** * Creates a XmlaOlap4jConnectionJdbc4. * * @param factory Factory * @param driver Driver * @param proxy Proxy * @param url URL * @param info Extra properties * @throws SQLException on error */ public XmlaOlap4jConnectionJdbc4( Factory factory, XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { super(factory, driver, proxy, url, info); } } private static class XmlaOlap4jCellSetJdbc4 extends FactoryJdbc4Plus.AbstractCellSet { /** * Creates an XmlaOlap4jCellSetJdbc4. * * @param olap4jStatement Statement * @throws OlapException on error */ XmlaOlap4jCellSetJdbc4( XmlaOlap4jStatement olap4jStatement) throws OlapException { super(olap4jStatement); } } private static class XmlaOlap4jStatementJdbc4 extends XmlaOlap4jStatement { /** * Creates a XmlaOlap4jStatementJdbc4. * * @param olap4jConnection Connection */ XmlaOlap4jStatementJdbc4( XmlaOlap4jConnection olap4jConnection) { super(olap4jConnection); } } private static class XmlaOlap4jPreparedStatementJdbc4 extends FactoryJdbc4Plus.AbstractPreparedStatement { /** * Creates a XmlaOlap4jPreparedStatementJdbc4. * * @param olap4jConnection Connection * @param mdx MDX query text * @throws OlapException on error */ XmlaOlap4jPreparedStatementJdbc4( XmlaOlap4jConnection olap4jConnection, String mdx) throws OlapException { super(olap4jConnection, mdx); } } private static class XmlaOlap4jDatabaseMetaDataJdbc4 extends FactoryJdbc4Plus.AbstractDatabaseMetaData { /** * Creates an XmlaOlap4jDatabaseMetaDataJdbc4. * * @param olap4jConnection Connection */ XmlaOlap4jDatabaseMetaDataJdbc4( XmlaOlap4jConnection olap4jConnection) { super(olap4jConnection); } } } // End FactoryJdbc4Impl.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/Factory.java0000644000175000017500000000667711707255006022401 0ustar drazzibdrazzib/* // $Id: Factory.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.OlapStatement; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import java.sql.*; import java.util.List; import java.util.Properties; /** * Instantiates classes to implement the olap4j API against the * an XML for Analysis provider. * *

There are implementations for JDBC 3.0 (which occurs in JDK 1.5) * and JDBC 4.0 (which occurs in JDK 1.6). * * @author jhyde * @version $Id: Factory.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 14, 2007 */ interface Factory { /** * Creates a connection. * * @param driver Driver * @param proxy Proxy (for submitting requests, via HTTP or otherwise) * @param url URL of server * @param info Properties defining the connection * @return Connection * @throws SQLException on error */ Connection newConnection( XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException; /** * Creates an empty result set. * * @param olap4jConnection Connection * @return Result set */ EmptyResultSet newEmptyResultSet( XmlaOlap4jConnection olap4jConnection); /** * Creates a result set with a fixed set of rows. * * @param olap4jConnection Connection * @param headerList Column headers * @param rowList Row values * @return Result set */ ResultSet newFixedResultSet( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList); /** * Creates a cell set. * * @param olap4jStatement Statement * @return Cell set * @throws OlapException on error */ XmlaOlap4jCellSet newCellSet( XmlaOlap4jStatement olap4jStatement) throws OlapException; /** * Creates a statement. * * @param olap4jConnection Connection * @return Statement */ XmlaOlap4jStatement newStatement( XmlaOlap4jConnection olap4jConnection); /** * Creates a prepared statement. * * @param mdx MDX query text * @param olap4jConnection Connection * @return Prepared statement * @throws OlapException on error */ XmlaOlap4jPreparedStatement newPreparedStatement( String mdx, XmlaOlap4jConnection olap4jConnection) throws OlapException; /** * Creates a metadata object. * * @param olap4jConnection Connection * @return Metadata object */ XmlaOlap4jDatabaseMetaData newDatabaseMetaData( XmlaOlap4jConnection olap4jConnection); } // End Factory.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jLevel.java0000644000175000017500000001724411707255006023725 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jLevel.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.*; import org.olap4j.metadata.*; import java.util.Arrays; import java.util.List; /** * Implementation of {@link org.olap4j.metadata.Level} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jLevel.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 4, 2007 */ class XmlaOlap4jLevel extends XmlaOlap4jElement implements Level, Named { final XmlaOlap4jHierarchy olap4jHierarchy; private final int depth; private final Type type; private final int cardinality; private final NamedList propertyList; final NamedList memberList; private final boolean calculated; /** * Creates an XmlaOlap4jLevel. * * @param olap4jHierarchy Hierarchy * @param uniqueName Unique name * @param name Name * @param caption Caption * @param description Description * @param depth Distance to root * @param type Level type * @param calculated Whether level is calculated * @param cardinality Number of members in this level */ XmlaOlap4jLevel( final XmlaOlap4jHierarchy olap4jHierarchy, String uniqueName, String name, String caption, String description, int depth, Type type, boolean calculated, int cardinality) { super(uniqueName, name, caption, description); assert olap4jHierarchy != null; this.type = type; this.calculated = calculated; this.cardinality = cardinality; this.depth = depth; this.olap4jHierarchy = olap4jHierarchy; String[] levelRestrictions = { "CATALOG_NAME", olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema.olap4jCatalog.getName(), "SCHEMA_NAME", olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema.getName(), "CUBE_NAME", olap4jHierarchy.olap4jDimension.olap4jCube.getName(), "DIMENSION_UNIQUE_NAME", olap4jHierarchy.olap4jDimension.getUniqueName(), "HIERARCHY_UNIQUE_NAME", olap4jHierarchy.getUniqueName(), "LEVEL_UNIQUE_NAME", getUniqueName() }; this.propertyList = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_PROPERTIES, new XmlaOlap4jConnection.Context(this), new XmlaOlap4jConnection.PropertyHandler(), levelRestrictions); try { if (olap4jHierarchy.olap4jDimension.getDimensionType() == Dimension.Type.MEASURE) { String[] restrictions = { "CATALOG_NAME", olap4jHierarchy.olap4jDimension.olap4jCube.olap4jSchema .olap4jCatalog.getName(), "SCHEMA_NAME", olap4jHierarchy.olap4jDimension.olap4jCube.olap4jSchema .getName(), "CUBE_NAME", olap4jHierarchy.olap4jDimension.olap4jCube.getName() }; this.memberList = Olap4jUtil.cast( new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEASURES, new XmlaOlap4jConnection.Context( olap4jHierarchy.olap4jDimension .olap4jCube.olap4jSchema .olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection, olap4jHierarchy.olap4jDimension .olap4jCube.olap4jSchema .olap4jCatalog.olap4jDatabaseMetaData, olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema.olap4jCatalog, olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema, olap4jHierarchy.olap4jDimension.olap4jCube, olap4jHierarchy.olap4jDimension, olap4jHierarchy, this), new XmlaOlap4jConnection.MeasureHandler(), restrictions)); } else { this.memberList = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, new XmlaOlap4jConnection.Context( olap4jHierarchy.olap4jDimension.olap4jCube.olap4jSchema .olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection, olap4jHierarchy.olap4jDimension.olap4jCube.olap4jSchema .olap4jCatalog.olap4jDatabaseMetaData, olap4jHierarchy.olap4jDimension.olap4jCube.olap4jSchema .olap4jCatalog, olap4jHierarchy.olap4jDimension.olap4jCube.olap4jSchema, olap4jHierarchy.olap4jDimension.olap4jCube, olap4jHierarchy.olap4jDimension, olap4jHierarchy, this), new XmlaOlap4jConnection.MemberHandler(), levelRestrictions); } } catch (OlapException e) { throw new RuntimeException("Programming error", e); } } public int getDepth() { return depth; } public Hierarchy getHierarchy() { return olap4jHierarchy; } public Dimension getDimension() { return olap4jHierarchy.olap4jDimension; } public boolean isCalculated() { return calculated; } public Type getLevelType() { return type; } public NamedList getProperties() { final NamedList list = new ArrayNamedListImpl() { protected String getName(Property property) { return property.getName(); } }; // standard properties first list.addAll( Arrays.asList(Property.StandardMemberProperty.values())); // then level-specific properties list.addAll(propertyList); return list; } public List getMembers() throws OlapException { return Olap4jUtil.cast(this.memberList); } public int getCardinality() { return cardinality; } public boolean equals(Object obj) { return (obj instanceof XmlaOlap4jLevel) && this.uniqueName.equals( ((XmlaOlap4jLevel) obj).getUniqueName()); } } // End XmlaOlap4jLevel.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jProperty.java0000644000175000017500000000470211707255006024475 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jProperty.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.impl.Named; import org.olap4j.metadata.Datatype; import org.olap4j.metadata.Property; import java.util.Set; /** * Implementation of {@link org.olap4j.metadata.Property} * for properties defined as part of the definition of a level or measure * from XML/A providers. * * @see org.olap4j.driver.xmla.XmlaOlap4jCellProperty * @see org.olap4j.driver.xmla.XmlaOlap4jCellSetMemberProperty * * @author jhyde * @version $Id: XmlaOlap4jProperty.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 9, 2007 */ class XmlaOlap4jProperty extends XmlaOlap4jElement implements Property, Named { private final Datatype datatype; private final Set type; private final ContentType contentType; XmlaOlap4jProperty( String uniqueName, String name, String caption, String description, Datatype datatype, Set type, ContentType contentType) { super(uniqueName, name, caption, description); this.contentType = contentType; assert datatype != null; assert type != null; this.datatype = datatype; this.type = type; } public Datatype getDatatype() { return datatype; } public Set getType() { return type; } public ContentType getContentType() { return contentType; } public boolean equals(Object obj) { return (obj instanceof XmlaOlap4jProperty) && this.uniqueName.equals( ((XmlaOlap4jProperty) obj).getUniqueName()); } } // End XmlaOlap4jProperty.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/FactoryJdbc4Plus.java0000644000175000017500000006605311707255006024106 0ustar drazzibdrazzib/* // $Id: FactoryJdbc4Plus.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.*; import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; import java.io.InputStream; import java.io.Reader; import java.sql.*; import java.util.*; /** * Abstract JDBC classes, for JDBC 4.0 and 4.1. * * @author jhyde * @version $Id: FactoryJdbc4Plus.java 483 2012-01-05 23:43:18Z jhyde $ */ class FactoryJdbc4Plus { private FactoryJdbc4Plus() { } static abstract class AbstractEmptyResultSet extends EmptyResultSet { /** * Creates an AbstractEmptyResultSet. * * @param olap4jConnection Connection * @param headerList Column names * @param rowList List of row values */ AbstractEmptyResultSet( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { super(olap4jConnection, headerList, rowList); } // implement java.sql.ResultSet methods // introduced in JDBC 4.0/JDK 1.6 public RowId getRowId(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public RowId getRowId(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateRowId(int columnIndex, RowId x) throws SQLException { throw new UnsupportedOperationException(); } public void updateRowId(String columnLabel, RowId x) throws SQLException { throw new UnsupportedOperationException(); } public int getHoldability() throws SQLException { throw new UnsupportedOperationException(); } public boolean isClosed() throws SQLException { throw new UnsupportedOperationException(); } public void updateNString( int columnIndex, String nString) throws SQLException { throw new UnsupportedOperationException(); } public void updateNString( String columnLabel, String nString) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob(int columnIndex, NClob nClob) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( String columnLabel, NClob nClob) throws SQLException { throw new UnsupportedOperationException(); } public NClob getNClob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public NClob getNClob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public SQLXML getSQLXML(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public SQLXML getSQLXML(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateSQLXML( int columnIndex, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } public void updateSQLXML( String columnLabel, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } public String getNString(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public String getNString(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Reader getNCharacterStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Reader getNCharacterStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( int columnIndex, Reader x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( int columnIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( int columnIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( int columnIndex, Reader x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( String columnLabel, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( String columnLabel, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( int columnIndex, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( String columnLabel, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob( int columnIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( int columnIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( int columnIndex, Reader x) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( int columnIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( int columnIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( int columnIndex, Reader x) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( String columnLabel, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( String columnLabel, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( int columnIndex, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( String columnLabel, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob( int columnIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( int columnIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } } static abstract class AbstractConnection extends XmlaOlap4jConnection implements OlapConnection { /** * Creates an AbstractConnection. * * @param factory Factory * @param driver Driver * @param proxy Proxy * @param url URL * @param info Extra properties * @throws SQLException on error */ AbstractConnection( Factory factory, XmlaOlap4jDriver driver, XmlaOlap4jProxy proxy, String url, Properties info) throws SQLException { super(factory, driver, proxy, url, info); } public OlapStatement createStatement() { return super.createStatement(); } public OlapDatabaseMetaData getMetaData() { return super.getMetaData(); } // implement java.sql.Connection methods // introduced in JDBC 4.0/JDK 1.6 public Clob createClob() throws SQLException { throw new UnsupportedOperationException(); } public Blob createBlob() throws SQLException { throw new UnsupportedOperationException(); } public NClob createNClob() throws SQLException { throw new UnsupportedOperationException(); } public SQLXML createSQLXML() throws SQLException { throw new UnsupportedOperationException(); } public boolean isValid(int timeout) throws SQLException { return !isClosed(); } public void setClientInfo( String name, String value) throws SQLClientInfoException { throw new UnsupportedOperationException(); } public void setClientInfo(Properties properties) throws SQLClientInfoException { throw new UnsupportedOperationException(); } public String getClientInfo(String name) throws SQLException { throw new UnsupportedOperationException(); } public Properties getClientInfo() throws SQLException { throw new UnsupportedOperationException(); } public Array createArrayOf( String typeName, Object[] elements) throws SQLException { throw new UnsupportedOperationException(); } public Struct createStruct( String typeName, Object[] attributes) throws SQLException { throw new UnsupportedOperationException(); } } static abstract class AbstractCellSet extends XmlaOlap4jCellSet { /** * Creates an AbstractCellSet. * * @param olap4jStatement Statement * @throws OlapException on error */ AbstractCellSet( XmlaOlap4jStatement olap4jStatement) throws OlapException { super(olap4jStatement); } public CellSetMetaData getMetaData() { return super.getMetaData(); } // implement java.sql.CellSet methods // introduced in JDBC 4.0/JDK 1.6 public RowId getRowId(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public RowId getRowId(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateRowId(int columnIndex, RowId x) throws SQLException { throw new UnsupportedOperationException(); } public void updateRowId(String columnLabel, RowId x) throws SQLException { throw new UnsupportedOperationException(); } public int getHoldability() throws SQLException { throw new UnsupportedOperationException(); } public boolean isClosed() throws SQLException { return closed; } public void updateNString( int columnIndex, String nString) throws SQLException { throw new UnsupportedOperationException(); } public void updateNString( String columnLabel, String nString) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob(int columnIndex, NClob nClob) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( String columnLabel, NClob nClob) throws SQLException { throw new UnsupportedOperationException(); } public NClob getNClob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public NClob getNClob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public SQLXML getSQLXML(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public SQLXML getSQLXML(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateSQLXML( int columnIndex, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } public void updateSQLXML( String columnLabel, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } public String getNString(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public String getNString(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Reader getNCharacterStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Reader getNCharacterStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( int columnIndex, Reader x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( int columnIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( int columnIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( int columnIndex, Reader x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( String columnLabel, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( String columnLabel, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( int columnIndex, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( String columnLabel, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob( int columnIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( int columnIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( int columnIndex, Reader x) throws SQLException { throw new UnsupportedOperationException(); } public void updateNCharacterStream( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( int columnIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( int columnIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( int columnIndex, Reader x) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( String columnLabel, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( String columnLabel, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( int columnIndex, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob( String columnLabel, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(int columnIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( int columnIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateNClob( String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } } static abstract class AbstractPreparedStatement extends XmlaOlap4jPreparedStatement { /** * Creates a AbstractPreparedStatement. * * @param olap4jConnection Connection * @param mdx MDX query text * @throws OlapException on error */ AbstractPreparedStatement( XmlaOlap4jConnection olap4jConnection, String mdx) throws OlapException { super(olap4jConnection, mdx); } public CellSetMetaData getMetaData() { return super.getMetaData(); } // implement java.sql.PreparedStatement methods // introduced in JDBC 4.0/JDK 1.6 public void setRowId(int parameterIndex, RowId x) throws SQLException { throw new UnsupportedOperationException(); } public void setNString( int parameterIndex, String value) throws SQLException { throw new UnsupportedOperationException(); } public void setNCharacterStream( int parameterIndex, Reader value, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setNClob(int parameterIndex, NClob value) throws SQLException { throw new UnsupportedOperationException(); } public void setClob( int parameterIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setBlob( int parameterIndex, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setNClob( int parameterIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setSQLXML( int parameterIndex, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } public void setAsciiStream( int parameterIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setBinaryStream( int parameterIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setCharacterStream( int parameterIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setAsciiStream( int parameterIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void setBinaryStream( int parameterIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void setCharacterStream( int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void setNCharacterStream( int parameterIndex, Reader value) throws SQLException { throw new UnsupportedOperationException(); } public void setClob(int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void setBlob( int parameterIndex, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } public void setNClob( int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } } static abstract class AbstractDatabaseMetaData extends XmlaOlap4jDatabaseMetaData { /** * Creates an AbstractDatabaseMetaData. * * @param olap4jConnection Connection */ AbstractDatabaseMetaData( XmlaOlap4jConnection olap4jConnection) { super(olap4jConnection); } public OlapConnection getConnection() { return super.getConnection(); } // implement java.sql.DatabaseMetaData methods // introduced in JDBC 4.0/JDK 1.6 public RowIdLifetime getRowIdLifetime() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getSchemas( String catalog, String schemaPattern) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { throw new UnsupportedOperationException(); } public boolean autoCommitFailureClosesAllResultSets() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getClientInfoProperties() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getFunctions( String catalog, String schemaPattern, String functionNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getFunctionColumns( String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } } } // End FactoryJdbc4Plus.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jMeasure.java0000644000175000017500000000544411707255006024256 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jMeasure.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.impl.Named; import org.olap4j.metadata.*; import java.util.Collections; /** * Implementation of {@link org.olap4j.metadata.Measure} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jMeasure.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 4, 2007 */ class XmlaOlap4jMeasure extends XmlaOlap4jMember implements Measure, Named { private final Aggregator aggregator; private final Datatype datatype; private final boolean visible; /** * Creates an XmlaOlap4jMeasure. * * @param olap4jLevel Level * @param uniqueName Unique name * @param name Name * @param caption Caption * @param description Description * @param parentMemberUniqueName Unique name of parent, or null if no parent * @param aggregator Aggregator * @param datatype Data type * @param visible Whether visible * @param ordinal Ordinal in its hierarchy */ XmlaOlap4jMeasure( XmlaOlap4jLevel olap4jLevel, String uniqueName, String name, String caption, String description, String parentMemberUniqueName, Aggregator aggregator, Datatype datatype, boolean visible, int ordinal) { super( olap4jLevel, uniqueName, name, caption, description, parentMemberUniqueName, aggregator == Aggregator.CALCULATED ? Type.FORMULA : Type.MEASURE, 0, ordinal, Collections.emptyMap()); assert olap4jLevel.olap4jHierarchy.olap4jDimension.type == Dimension.Type.MEASURE; this.aggregator = aggregator; this.datatype = datatype; this.visible = visible; } public Aggregator getAggregator() { return aggregator; } public Datatype getDatatype() { return datatype; } public boolean isVisible() { return visible; } } // End XmlaOlap4jMeasure.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jPositionMember.java0000644000175000017500000002173411707255006025611 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jPositionMember.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.ArrayMap; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.*; import java.util.*; /** * Implementation of {@link org.olap4j.metadata.Member} * for positions on an axis in a cell set * from an XML/A provider. * *

This class is necessary because a member can have different properties * when it is retrieved as part of a cell set than if it is retrieved by * querying schema metadata (e.g. using * {@link Cube#lookupMember(java.util.List)}. * XmlaOlap4jPositionMember wraps the schema member (which might potentially * be cached between queries - even though today it is not) and adds extra * properties. All other methods are delegated to the underlying member.

* * @author jhyde * @version $Id: XmlaOlap4jPositionMember.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 7, 2007 */ class XmlaOlap4jPositionMember implements XmlaOlap4jMemberBase { private final XmlaOlap4jMemberBase member; private final Map propertyValues; /** * Creates a XmlaOlap4jPositionMember. * * @param member Underlying member * @param propertyValues Property values */ XmlaOlap4jPositionMember( XmlaOlap4jMemberBase member, Map propertyValues) { assert member != null; assert propertyValues != null; this.member = member; this.propertyValues = new ArrayMap(propertyValues); } public boolean equals(Object obj) { if (obj instanceof XmlaOlap4jPositionMember) { XmlaOlap4jPositionMember that = (XmlaOlap4jPositionMember) obj; return this.member.equals(that.member); } else if (obj instanceof XmlaOlap4jMember) { XmlaOlap4jMember that = (XmlaOlap4jMember) obj; return this.member.equals(that); } else { return super.equals(obj); } } public int hashCode() { return member.hashCode(); } public XmlaOlap4jCube getCube() { return member.getCube(); } public XmlaOlap4jConnection getConnection() { return member.getConnection(); } public XmlaOlap4jCatalog getCatalog() { return member.getCatalog(); } public Map getPropertyValueMap() { return new ChainedMap( propertyValues, member.getPropertyValueMap()); } public NamedList getChildMembers() throws OlapException { return member.getChildMembers(); } public int getChildMemberCount() throws OlapException { return member.getChildMemberCount(); } public Member getParentMember() { return member.getParentMember(); } public Level getLevel() { return member.getLevel(); } public Hierarchy getHierarchy() { return member.getHierarchy(); } public Dimension getDimension() { return member.getDimension(); } public Type getMemberType() { return member.getMemberType(); } public boolean isAll() { return member.isAll(); } public boolean isChildOrEqualTo(Member member) { return this.member.isChildOrEqualTo(member); } public boolean isCalculated() { return member.isCalculated(); } public int getSolveOrder() { return member.getSolveOrder(); } public ParseTreeNode getExpression() { return member.getExpression(); } public List getAncestorMembers() { return member.getAncestorMembers(); } public boolean isCalculatedInQuery() { return member.isCalculatedInQuery(); } public Object getPropertyValue(Property property) throws OlapException { if (propertyValues.containsKey(property)) { return propertyValues.get(property); } return member.getPropertyValue(property); } public String getPropertyFormattedValue(Property property) throws OlapException { // REVIEW: Formatted value is not available for properties which // come back as part of axis tuple. Unformatted property is best we // can do. if (propertyValues.containsKey(property)) { return String.valueOf(propertyValues.get(property)); } return member.getPropertyFormattedValue(property); } public void setProperty( Property property, Object value) throws OlapException { throw new UnsupportedOperationException(); } public NamedList getProperties() { return member.getProperties(); } public int getOrdinal() { return member.getOrdinal(); } public boolean isHidden() { return member.isHidden(); } public int getDepth() { try { final Object value = XmlaOlap4jMember.getPropertyValue( Property.StandardMemberProperty.DEPTH, member, getPropertyValueMap()); return XmlaOlap4jMember.toInteger(value); } catch (OlapException e) { // should not happen; only CHILDREN_CARDINALITY can potentially // give an error throw new RuntimeException(e); } } public Member getDataMember() { return member.getDataMember(); } public String getName() { return member.getName(); } public String getUniqueName() { return member.getUniqueName(); } public String getCaption() { return member.getCaption(); } public String getDescription() { return member.getDescription(); } public boolean isVisible() { return member.isVisible(); } /** * Read-only map that contains the union of two maps. */ private static class ChainedMap implements Map { private final Map map; private final Map next; /** * Creates a ChainedMap. * * @param map First map in the chain * @param next Next map in the chain */ ChainedMap( Map map, Map next) { this.map = map; this.next = next; } public int size() { int n = next.size(); for (K k : map.keySet()) { //noinspection SuspiciousMethodCalls if (!next.containsKey(k)) { ++n; } } return n; } public boolean isEmpty() { return map.isEmpty() && next.isEmpty(); } public boolean containsKey(Object key) { return map.containsKey(key) || next.containsKey(key); } public boolean containsValue(Object value) { return map.containsValue(value) || next.containsValue(value); } public V get(Object key) { //noinspection SuspiciousMethodCalls if (map.containsKey(key)) { return map.get(key); } else { return next.get(key); } } public V put(K key, V value) { throw new UnsupportedOperationException("read only"); } public V remove(Object key) { throw new UnsupportedOperationException("read only"); } public void putAll(Map t) { throw new UnsupportedOperationException("read only"); } public void clear() { throw new UnsupportedOperationException("read only"); } public Set keySet() { throw new UnsupportedOperationException("need to implement"); } public Collection values() { throw new UnsupportedOperationException("need to implement"); } public Set> entrySet() { throw new UnsupportedOperationException("need to implement"); } } } // End XmlaOlap4jPositionMember.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jPosition.java0000644000175000017500000000306111707255004024450 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jPosition.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.Position; import org.olap4j.metadata.Member; import java.util.List; /** * Implementation of {@link org.olap4j.Position} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jPosition.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 5, 2007 */ class XmlaOlap4jPosition implements Position { private final int ordinal; private final List members; public XmlaOlap4jPosition(List members, int ordinal) { this.members = members; this.ordinal = ordinal; } public List getMembers() { return members; } public int getOrdinal() { return ordinal; } } // End XmlaOlap4jPosition.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/DeferredNamedListImpl.java0000644000175000017500000001023111707255006025112 0ustar drazzibdrazzib/* // $Id: DeferredNamedListImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.Named; import org.olap4j.impl.NamedListImpl; import org.olap4j.metadata.NamedList; import java.util.AbstractList; /** * Named list which instantiates itself on first use. * *

DeferredNamedListImpl is useful way to load an object model * representing a hierarchical schema. If a catalog contains schemas, which * contain cubes, which contain dimensions, and so forth, and if all * collections loaded immediately, loading the catalog would immediately load * all sub-objects into memory, taking a lot of memory and time. * *

This class is not gc-friendly at present. Once populated, * DeferredNamedListImpl holds hard references * to the objects it contains, so they are not available to be * garbage-collected. Support for weak references might be a future enhancement * to this class.

* * @author jhyde * @version $Id: DeferredNamedListImpl.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 4, 2007 */ class DeferredNamedListImpl extends AbstractList implements NamedList { private final NamedList list = new NamedListImpl(); private State state = State.NEW; protected final XmlaOlap4jConnection.MetadataRequest metadataRequest; protected final XmlaOlap4jConnection.Context context; protected final XmlaOlap4jConnection.Handler handler; protected final Object[] restrictions; DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest metadataRequest, XmlaOlap4jConnection.Context context, XmlaOlap4jConnection.Handler handler, Object[] restrictions) { this.metadataRequest = metadataRequest; this.context = context; this.handler = handler; this.restrictions = (restrictions == null) ? new Object[0] : restrictions; } /** * Flushes the contents of the list. Next access will re-populate. */ void reset() { state = State.NEW; list.clear(); } private NamedList getList() { switch (state) { case POPULATING: throw new RuntimeException("recursive population"); case NEW: try { state = State.POPULATING; populateList(list); state = State.POPULATED; } catch (OlapException e) { state = State.NEW; // TODO: fetch metadata on getCollection() method, so we // can't get an exception while traversing the list throw new RuntimeException(e); } // fall through case POPULATED: default: return list; } } public T get(int index) { return getList().get(index); } public int size() { return getList().size(); } public T get(String name) { return getList().get(name); } public int indexOfName(String name) { return getList().indexOfName(name); } protected void populateList(NamedList list) throws OlapException { context.olap4jConnection.populateList( list, context, metadataRequest, handler, restrictions); } private enum State { NEW, POPULATING, POPULATED } } // End DeferredNamedListImpl.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jMemberBase.java0000644000175000017500000000353411707255006024655 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jMemberBase.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.metadata.Member; import org.olap4j.metadata.Property; import java.util.Map; /** * Core interface shared by all implementations of {@link Member} in the XMLA * driver. * *

This interface is private within the {@code org.olap4j.driver.xmla} * package. The methods in this interface are NOT part of the public olap4j API. * * @author jhyde * @version $Id: XmlaOlap4jMemberBase.java 482 2012-01-05 23:27:27Z jhyde $ * @since Nov 1, 2008 */ interface XmlaOlap4jMemberBase extends Member { /** * Returns the cube this member belongs to. */ XmlaOlap4jCube getCube(); /** * Returns the connection that created this member. */ XmlaOlap4jConnection getConnection(); /** * Returns the catalog that this member belongs to. */ XmlaOlap4jCatalog getCatalog(); /** * Returns the set of property values, keyed by property. */ Map getPropertyValueMap(); } // End XmlaOlap4jMemberBase.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jHierarchy.java0000644000175000017500000001036411707255006024570 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jHierarchy.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.*; import org.olap4j.metadata.*; import java.util.List; /** * Implementation of {@link org.olap4j.metadata.Hierarchy} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jHierarchy.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 4, 2007 */ class XmlaOlap4jHierarchy extends XmlaOlap4jElement implements Hierarchy, Named { final XmlaOlap4jDimension olap4jDimension; final NamedList levels; private final boolean all; private final String defaultMemberUniqueName; XmlaOlap4jHierarchy( XmlaOlap4jDimension olap4jDimension, String uniqueName, String name, String caption, String description, boolean all, String defaultMemberUniqueName) throws OlapException { super(uniqueName, name, caption, description); assert olap4jDimension != null; this.olap4jDimension = olap4jDimension; this.all = all; this.defaultMemberUniqueName = defaultMemberUniqueName; String[] hierarchyRestrictions = { "CATALOG_NAME", olap4jDimension.olap4jCube.olap4jSchema.olap4jCatalog.getName(), "SCHEMA_NAME", olap4jDimension.olap4jCube.olap4jSchema.getName(), "CUBE_NAME", olap4jDimension.olap4jCube.getName(), "DIMENSION_UNIQUE_NAME", olap4jDimension.getUniqueName(), "HIERARCHY_UNIQUE_NAME", getUniqueName() }; this.levels = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_LEVELS, new XmlaOlap4jConnection.Context( olap4jDimension.olap4jCube.olap4jSchema.olap4jCatalog .olap4jDatabaseMetaData.olap4jConnection, olap4jDimension.olap4jCube.olap4jSchema.olap4jCatalog .olap4jDatabaseMetaData, olap4jDimension.olap4jCube.olap4jSchema.olap4jCatalog, olap4jDimension.olap4jCube.olap4jSchema, olap4jDimension.olap4jCube, olap4jDimension, this, null), new XmlaOlap4jConnection.LevelHandler(olap4jDimension.olap4jCube), hierarchyRestrictions); } public Dimension getDimension() { return olap4jDimension; } public NamedList getLevels() { return Olap4jUtil.cast(levels); } public boolean hasAll() { return all; } public Member getDefaultMember() throws OlapException { if (defaultMemberUniqueName == null) { return null; } return olap4jDimension.olap4jCube.getMetadataReader() .lookupMemberByUniqueName( defaultMemberUniqueName); } public NamedList getRootMembers() throws OlapException { final List memberList = olap4jDimension.olap4jCube.getMetadataReader().getLevelMembers( levels.get(0)); final NamedList list = new NamedListImpl(memberList); return Olap4jUtil.cast(list); } public boolean equals(Object obj) { return (obj instanceof XmlaOlap4jHierarchy) && this.uniqueName.equals( ((XmlaOlap4jHierarchy) obj).getUniqueName()); } } // End XmlaOlap4jHierarchy.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jNamedSet.java0000644000175000017500000000374211707255006024354 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jNamedSet.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.impl.Named; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.Cube; import org.olap4j.metadata.NamedSet; /** * Implementation of {@link org.olap4j.metadata.NamedSet} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jNamedSet.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 4, 2007 */ class XmlaOlap4jNamedSet implements NamedSet, Named { private final XmlaOlap4jCube olap4jCube; private final String name; XmlaOlap4jNamedSet( XmlaOlap4jCube olap4jCube, String name) { this.olap4jCube = olap4jCube; this.name = name; } public Cube getCube() { return olap4jCube; } public ParseTreeNode getExpression() { throw new UnsupportedOperationException(); } public String getName() { return name; } public String getUniqueName() { return name; } public String getCaption() { return name; } public String getDescription() { return ""; } public boolean isVisible() { return true; } } // End XmlaOlap4jNamedSet.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/0000755000175000017500000000000011547572724021303 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java0000644000175000017500000002344311707255002026535 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCookieManager.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; import java.net.URL; import java.net.URLConnection; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** *

CookieManager is a simple utility for handling cookies when working * with java.net.URL and java.net.URLConnection * objects. * *

This code was taken from http://www.hccp.org/java-net-cookie-how-to.html * and modified by Luc Boudreau to support concurrent access and be more * thread safe. * *

Here's a few use cases examples... * *


* *

Cookiemanager cm = new CookieManager(); *

URL url = new URL("http://www.hccp.org/test/cookieTest.jsp"); * *

. . . * *

// getting cookies: *

URLConnection conn = url.openConnection(); *

conn.connect(); * *

// setting cookies *

cm.storeCookies(conn); *

cm.setCookies(url.openConnection()); * *


* * @author Ian Brown * @version $Id: XmlaOlap4jCookieManager.java 482 2012-01-05 23:27:27Z jhyde $ **/ @SuppressWarnings("unchecked") class XmlaOlap4jCookieManager { private Map store; private static final String SET_COOKIE = "Set-Cookie"; private static final String COOKIE_VALUE_DELIMITER = ";"; private static final String PATH = "path"; private static final String EXPIRES = "expires"; private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z"; private static final String SET_COOKIE_SEPARATOR = "; "; private static final String COOKIE = "Cookie"; private static final char NAME_VALUE_SEPARATOR = '='; private static final char DOT = '.'; private DateFormat dateFormat; private boolean debug = false; public XmlaOlap4jCookieManager() { store = new ConcurrentHashMap(); dateFormat = new SimpleDateFormat(DATE_FORMAT); } /** * Retrieves and stores cookies returned by the host on the other side * of the the open java.net.URLConnection. * * The connection MUST have been opened using the connect() * method or a IOException will be thrown. * * @param conn a java.net.URLConnection - must be open, * or IOException will be thrown * @throws java.io.IOException Thrown if conn is not open. */ public void storeCookies(URLConnection conn) { // Determines the domain from where these cookies are being sent String domain = getDomainFromHost(conn.getURL().getHost()); Map domainStore; // Where we will store cookies for this domain // Checks the store to see if we have an entry for this domain if (store.containsKey(domain)) { // we do, so lets retrieve it from the store domainStore = (Map) store.get(domain); } else { // we don't, so let's create it and put it in the store domainStore = new ConcurrentHashMap(); store.put(domain, domainStore); } // OK, now we are ready to get the cookies out of the URLConnection String headerName = null; for (int i = 1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) { if (headerName.equalsIgnoreCase(SET_COOKIE)) { Map cookie = new ConcurrentHashMap(); StringTokenizer st = new StringTokenizer( conn.getHeaderField(i), COOKIE_VALUE_DELIMITER); // the specification dictates that the first name/value pair // in the string is the cookie name and value, so let's handle // them as a special case: if (st.hasMoreTokens()) { String token = st.nextToken(); String name = token.substring( 0, token.indexOf(NAME_VALUE_SEPARATOR)); String value = token.substring( token .indexOf(NAME_VALUE_SEPARATOR) + 1, token.length()); domainStore.put(name, cookie); cookie.put(name, value); if (this.debug) { System.out.println( "Saving cookie : " + name + "=" + value); } } while (st.hasMoreTokens()) { String token = st.nextToken(); // Check if the separator does exist // The other attributes are not stored (Ex: HttpOnly) int separatorIndex = token.indexOf(NAME_VALUE_SEPARATOR); if (separatorIndex > 0) { String tokenName = token.substring( 0, separatorIndex) .toLowerCase(); String tokenValue = token.substring( separatorIndex + 1, token.length()); cookie.put(tokenName, tokenValue); if (this.debug) { System.out.println( "Saving cookie : " + tokenName + "=" + tokenValue); } } } } } } /** * Prior to opening a URLConnection, calling this method will set all * unexpired cookies that match the path or subpaths for thi underlying URL. * *

The connection MUST NOT have been opened method or an IOException will * be thrown. * * @param conn a java.net.URLConnection - must NOT be open, or * IOException will be thrown * * @throws java.io.IOException Thrown if conn has already been * opened. */ public void setCookies(URLConnection conn) { // Determines the domain and path to retrieve the appropriate cookies URL url = conn.getURL(); String domain = getDomainFromHost(url.getHost()); String path = url.getPath(); Map domainStore = (Map) store.get(domain); if (domainStore == null) { return; } StringBuffer cookieStringBuffer = new StringBuffer(); Iterator cookieNames = domainStore.keySet().iterator(); while (cookieNames.hasNext()) { String cookieName = (String) cookieNames.next(); Map cookie = (Map) domainStore.get(cookieName); // check cookie to ensure path matches and cookie is not expired // if all is cool, add cookie to header string if (comparePaths((String) cookie.get(PATH), path) && isNotExpired((String) cookie.get(EXPIRES))) { cookieStringBuffer.append(cookieName); cookieStringBuffer.append("="); cookieStringBuffer.append((String) cookie.get(cookieName)); if (cookieNames.hasNext()) { cookieStringBuffer.append(SET_COOKIE_SEPARATOR); } } } try { if (this.debug && !(cookieStringBuffer.toString().equals(""))) { System.out.println( "Using cookie : " + cookieStringBuffer.toString()); } conn.setRequestProperty(COOKIE, cookieStringBuffer.toString()); } catch (java.lang.IllegalStateException ise) { throw new RuntimeException( "Illegal State! Cookies cannot be set on a URLConnection that is already connected. Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect()."); } } private String getDomainFromHost(String host) { if (host.indexOf(DOT) != host.lastIndexOf(DOT)) { return host.substring(host.indexOf(DOT) + 1); } else { return host; } } private boolean isNotExpired(String cookieExpires) { if (cookieExpires == null) { return true; } Date now = new Date(); try { return (now.compareTo(dateFormat.parse(cookieExpires))) <= 0; } catch (java.text.ParseException pe) { pe.printStackTrace(); return false; } } private boolean comparePaths(String cookiePath, String targetPath) { if (cookiePath == null) { return true; } else if (cookiePath.equals("/")) { return true; } else if (targetPath.regionMatches( 0, cookiePath, 0, cookiePath.length())) { return true; } else { return false; } } /** * Returns a string representation of stored cookies organized by domain. */ public String toString() { return store.toString(); } } // End XmlaOlap4jCookieManager.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCachedProxy.java0000644000175000017500000000405311707255002026236 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCachedProxy.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; import org.olap4j.OlapException; import org.olap4j.driver.xmla.cache.XmlaOlap4jCache; import java.util.Map; /** * * Extended Proxy interface which supports cached SOAP calls. * * @author Luc Boudreau * @version $Id: XmlaOlap4jCachedProxy.java 482 2012-01-05 23:27:27Z jhyde $ * */ public interface XmlaOlap4jCachedProxy extends XmlaOlap4jProxy { /** *

Sets the cache class to use as a SOAP message cache. * *

Calling this method is not mandatory. If it isn't called, * no cache will be used and all SOAP requests will be sent to * the service end-point. * * @param configParameters This contains all the parameters used * to configure the Olap4j driver. It contains the full class name * of the cache implementation to use as well as the raw Cache * config parameters. * @param properties The properties to configure the cache, * so all config parameters which started * by Cache.* are inside this convenient thigny. * @see XmlaOlap4jCache */ void setCache( Map configParameters, Map properties) throws OlapException; } // End XmlaOlap4jCachedProxy.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java0000644000175000017500000002062411707255002027474 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jAbstractHttpProxy.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; import org.olap4j.OlapException; import org.olap4j.driver.xmla.*; import org.olap4j.driver.xmla.cache.XmlaOlap4jCache; import java.net.URL; import java.net.URLConnection; import java.util.Map; import java.util.concurrent.Future; /** *

Abstract implementation of Proxy which adds a SOAP * cache layer between the driver and its proxy implementations. * It can be configured via the setCache() method, as instructed in * {@link XmlaOlap4jCachedProxy} interface. * *

It also offers helper methods to keep track of * the HTTP cookies and sends them back * to the server along with queries. The useful methods are * saveCookies(URL) and useCookies(URL). * * @author Luc Boudreau * @version $Id: XmlaOlap4jAbstractHttpProxy.java 482 2012-01-05 23:27:27Z jhyde $ */ abstract class XmlaOlap4jAbstractHttpProxy implements XmlaOlap4jCachedProxy { private final XmlaHelper helper = new XmlaHelper(); /** * Holds on to the cache implementation. */ private XmlaOlap4jCache cache = null; /** * Holds on to the connection name which is associated to this proxy. */ private String cacheId; /** * Keeps a link to the cookie manager instance. */ private XmlaOlap4jCookieManager cookieManager = null; /** * Creates an XmlaOlap4jAbstractHttpProxy. */ protected XmlaOlap4jAbstractHttpProxy() { } /** * Sends a request to a URL and returns the response. * * @param url Target URL * @param request Request string * @return Response */ public abstract byte[] getResponse( XmlaOlap4jServerInfos serverInfos, String request) throws XmlaOlap4jProxyException; /** * Submits a request for background execution. * * @param url URL * @param request Request * @return Future object representing the submitted job */ public abstract Future getResponseViaSubmit( XmlaOlap4jServerInfos serverInfos, String request); /** * Helper method to add cookies to a given connection. * @param urlConn The url connection to which we want the cookies * applied to. */ protected void useCookies(URLConnection urlConn) { // Initializes the cookie manager this.initCookieManager(); // Saves the current cookies this.cookieManager.setCookies(urlConn); } /** * Helper method to save cookies for later use. * @param urlConn The url connection for which we want the cookies * saved for later use. */ protected void saveCookies(URLConnection urlConn) { // Initializes the cookie manager this.initCookieManager(); // Saves the current cookies this.cookieManager.storeCookies(urlConn); } @SuppressWarnings("unchecked") public void setCache( Map config, Map properties) throws OlapException { try { // Loads the cache class Class clazz = Class.forName(config.get( XmlaOlap4jDriver.Property.CACHE.name())); // Instantiates it this.cache = (XmlaOlap4jCache) clazz.newInstance(); // Configures it this.cacheId = this.cache.setParameters(config, properties); } catch (ClassNotFoundException e) { throw helper.createException( "The specified cache class name could not be found : " + config.get(XmlaOlap4jDriver.Property.CACHE.name()), e); } catch (InstantiationException e) { throw helper.createException( "The specified cache class name could not be instanciated : " + config.get(XmlaOlap4jDriver.Property.CACHE.name()), e); } catch (IllegalAccessException e) { throw helper.createException( "An error was encountered while instanciating the cache : " + config.get(XmlaOlap4jDriver.Property.CACHE.name()), e); } catch (IllegalArgumentException e) { throw helper.createException( "An error was encountered while instanciating the cache : " + config.get(XmlaOlap4jDriver.Property.CACHE.name()), e); } catch (SecurityException e) { throw helper.createException( "An error was encountered while instanciating the cache : " + config.get(XmlaOlap4jDriver.Property.CACHE.name()), e); } } // implement XmlaOlap4jProxy public byte[] get( XmlaOlap4jServerInfos serverInfos, String request) throws XmlaOlap4jProxyException { byte[] response = null; // Tries to fetch from cache try { response = getFromCache( serverInfos.getUrl(), request.getBytes(getEncodingCharsetName())); // Returns the cached value if found if (response != null) { return response; } } catch (Exception e) { throw new XmlaOlap4jProxyException( "An exception was encountered while browsing the proxy cache.", e); } // Executes the query response = getResponse(serverInfos, request); try { // Adds to cache addToCache( serverInfos.getUrl(), request.getBytes(getEncodingCharsetName()), response); // Returns result return response; } catch (Exception e) { throw new XmlaOlap4jProxyException( "An exception was encountered while saving a response in the proxy cache.", e); } } /** * Tries to fetch a cached response from the cache implementation. * * @param url The url used to send the request * * @param request The SOAP request to cache * * @return either a response in a byte array or null * if the response is not in cache */ private byte[] getFromCache(final URL url, final byte[] request) throws OlapException { return (this.cache != null) ? this.cache.get(this.cacheId, url, request) : null; } /** * Caches an entry using the current cache implementation. * @param url The URL from which originated the request * @param request The SOAP request to cache * @param response The SOAP response to cache */ private void addToCache(URL url, byte[] request, byte[] response) throws OlapException { if (this.cache != null) { this.cache.put(this.cacheId, url, request, response); } } // implement XmlaOlap4jProxy public Future submit( final XmlaOlap4jServerInfos serverInfos, final String request) { // The submit operation doesn't need to be cached yet, since it will // call the get operation to fetch the data later on. It will get cached // then. // // I still overridden the submit method in case we need some caching // done in the end. - Luc return getResponseViaSubmit(serverInfos, request); } /** * Initializes the cookie manager. It is not initialized * by default because some proxy implementation might not need this * functionnality. */ private void initCookieManager() { if (this.cookieManager == null) { this.cookieManager = new XmlaOlap4jCookieManager(); } } } // End XmlaOlap4jAbstractHttpProxy.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxyException.java0000644000175000017500000000255611707255002027033 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jProxyException.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; /** * Gets thrown whenever an exception is encountered during the querying * of an XmlaOlap4jProxy subclass. * * @author Luc Boudreau * @version $Id: XmlaOlap4jProxyException.java 482 2012-01-05 23:27:27Z jhyde $ */ public class XmlaOlap4jProxyException extends Exception { private static final long serialVersionUID = 1729906649527317997L; public XmlaOlap4jProxyException(String message, Throwable cause) { super(message, cause); } } // End XmlaOlap4jProxyException.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/package.html0000644000175000017500000000012411421322450023535 0ustar drazzibdrazzib Provides proxy communications with XML/A servers. olap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java0000644000175000017500000001560611707255002026014 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jHttpProxy.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; import org.olap4j.driver.xmla.XmlaOlap4jDriver; import org.olap4j.driver.xmla.XmlaOlap4jServerInfos; import org.olap4j.impl.Base64; import java.io.*; import java.net.*; import java.util.concurrent.Future; /** * Extends the AbstractCachedProxy and serves as * a production ready http communication class. Every SOAP request * sends a POST call to the destination XMLA server and returns * the response as a byte array, conforming to the Proxy interface. * *

It also takes advantage of the AbstractHttpProxy cookie * managing facilities. All cookies received from the end point * server will be sent back if they are not expired and they also * conform to cookie domain rules. * * @author Luc Boudreau and Julian Hyde * @version $Id: XmlaOlap4jHttpProxy.java 482 2012-01-05 23:27:27Z jhyde $ */ public class XmlaOlap4jHttpProxy extends XmlaOlap4jAbstractHttpProxy { private final XmlaOlap4jDriver driver; /** * Creates a XmlaOlap4jHttpProxy. * * @param driver Driver */ public XmlaOlap4jHttpProxy( XmlaOlap4jDriver driver) { this.driver = driver; } private static final String DISCOVER = " 0) { baos.write(buf, 0, count); } // Save the returned cookies for later use this.saveCookies(urlConnection); return baos.toByteArray(); // All exceptions should be trapped here. // The response will only be available here anyways. } catch (Exception e) { // In order to prevent the JDK from keeping this connection // in WAIT mode, we need to empty the error stream cache. try { final int espCode = ((HttpURLConnection)urlConnection).getResponseCode(); InputStream errorStream = ((HttpURLConnection)urlConnection).getErrorStream(); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final byte[] buf = new byte[1024]; int count; if (errorStream != null) { while ((count = errorStream.read(buf)) > 0) { baos.write(buf, 0, count); } errorStream.close(); } baos.close(); } catch (IOException ex) { // Well, we tried. No point notifying the user here. } throw new XmlaOlap4jProxyException( "This proxy encountered an exception while processing the " + "query.", e); } } @Override public Future getResponseViaSubmit( final XmlaOlap4jServerInfos serverInfos, final String request) { return XmlaOlap4jDriver.getFuture(this, serverInfos, request); } // implement XmlaOlap4jProxy public String getEncodingCharsetName() { return "UTF-8"; } } // End XmlaOlap4jHttpProxy.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java0000644000175000017500000000405111707255002025144 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jProxy.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla.proxy; import org.olap4j.driver.xmla.XmlaOlap4jServerInfos; import java.util.concurrent.Future; /** * Defines a common set of methods for proxy objects. * @version $Id: XmlaOlap4jProxy.java 482 2012-01-05 23:27:27Z jhyde $ */ public interface XmlaOlap4jProxy { /** * Sends a request to a URL and returns the response. * * @param serverInfos Server infos. * @param request Request string * @return Response The byte array that contains the whole response * from the server. * @throws XmlaOlap4jProxyException If anything occurs during the * request execution. */ byte[] get( XmlaOlap4jServerInfos serverInfos, String request) throws XmlaOlap4jProxyException; /** * Submits a request for background execution. * * @param serverInfos Server infos. * @param request Request * @return Future object representing the submitted job */ Future submit( XmlaOlap4jServerInfos serverInfos, String request); /** * Returns the name of the character set use for encoding the XML * string. */ String getEncodingCharsetName(); } // End XmlaOlap4jProxy.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java0000644000175000017500000005367511707255006023544 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCube.java 486 2012-01-18 14:02:52Z pstoellberger $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapException; import org.olap4j.impl.*; import org.olap4j.mdx.IdentifierSegment; import org.olap4j.metadata.*; import java.lang.ref.SoftReference; import java.util.*; /** * Implementation of {@link Cube} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jCube.java 486 2012-01-18 14:02:52Z pstoellberger $ * @since Dec 4, 2007 */ class XmlaOlap4jCube implements Cube, Named { final XmlaOlap4jSchema olap4jSchema; private final String name; private final String caption; private final String description; final NamedList dimensions; final Map dimensionsByUname = new HashMap(); private NamedList hierarchies = null; final Map hierarchiesByUname = new HashMap(); final Map levelsByUname = new HashMap(); final List measures = new ArrayList(); private final NamedList namedSets; private final MetadataReader metadataReader; /** * Creates an XmlaOlap4jCube. * * @param olap4jSchema Schema * @param name Name * @param caption Caption * @param description Description * @throws org.olap4j.OlapException on error */ XmlaOlap4jCube( XmlaOlap4jSchema olap4jSchema, String name, String caption, String description) throws OlapException { assert olap4jSchema != null; assert description != null; assert name != null; this.olap4jSchema = olap4jSchema; this.name = name; this.caption = caption; this.description = description; final Map measuresMap = new HashMap(); this.metadataReader = new CachingMetadataReader( new RawMetadataReader(), measuresMap); // In case this is the dummy cube for shared dimensions stop here // to avoid unnecessary calls and errors with unique members if ("".equals(name)) { namedSets = null; dimensions = null; return; } final XmlaOlap4jConnection olap4jConnection = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; final XmlaOlap4jConnection.Context context = new XmlaOlap4jConnection.Context(this, null, null, null); String[] restrictions = { "CATALOG_NAME", olap4jSchema.olap4jCatalog.getName(), "SCHEMA_NAME", olap4jSchema.getName(), "CUBE_NAME", getName() }; this.dimensions = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_DIMENSIONS, context, new XmlaOlap4jConnection.DimensionHandler(this), restrictions); // populate measures up front; a measure is needed in every query olap4jConnection.populateList( measures, context, XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEASURES, new XmlaOlap4jConnection.MeasureHandler(), restrictions); for (XmlaOlap4jMeasure measure : measures) { measuresMap.put(measure.getUniqueName(), measure); } // populate named sets namedSets = new DeferredNamedListImpl( XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_SETS, context, new XmlaOlap4jConnection.NamedSetHandler(), restrictions); } public Schema getSchema() { return olap4jSchema; } public String getName() { return name; } public String getUniqueName() { return "[" + name + "]"; } public String getCaption() { return caption; } public String getDescription() { return description; } public boolean isVisible() { return true; } public NamedList getDimensions() { return Olap4jUtil.cast(dimensions); } public NamedList getHierarchies() { // This is a costly operation. It forces the init // of all dimensions and all hierarchies. // We defer it to this point. if (this.hierarchies == null) { this.hierarchies = new NamedListImpl(); for (XmlaOlap4jDimension dim : this.dimensions) { this.hierarchies.addAll(dim.hierarchies); } } return Olap4jUtil.cast(hierarchies); } public boolean isDrillThroughEnabled() { // XMLA does not implement drillthrough yet. return false; } public List getMeasures() { return Olap4jUtil.cast(measures); } public NamedList getSets() { return Olap4jUtil.cast(namedSets); } public Collection getSupportedLocales() { return Collections.singletonList(Locale.getDefault()); } public Member lookupMember( List segmentList) throws OlapException { StringBuilder buf = new StringBuilder(); for (IdentifierSegment segment : segmentList) { if (buf.length() > 0) { buf.append('.'); } buf.append(segment.toString()); } final String uniqueName = buf.toString(); return getMetadataReader().lookupMemberByUniqueName(uniqueName); } /** * Returns this cube's metadata reader. * *

Not part of public olap4j API. * * @return metadata reader */ MetadataReader getMetadataReader() { return metadataReader; } public List lookupMembers( Set treeOps, List nameParts) throws OlapException { StringBuilder buf = new StringBuilder(); for (IdentifierSegment namePart : nameParts) { if (buf.length() > 0) { buf.append('.'); } buf.append(namePart); } final String uniqueName = buf.toString(); final List list = new ArrayList(); getMetadataReader().lookupMemberRelatives( treeOps, uniqueName, list); return Olap4jUtil.cast(list); } /** * Abstract implementation of MemberReader that delegates all operations * to an underlying MemberReader. */ private static abstract class DelegatingMetadataReader implements MetadataReader { private final MetadataReader metadataReader; /** * Creates a DelegatingMetadataReader. * * @param metadataReader Underlying metadata reader */ DelegatingMetadataReader(MetadataReader metadataReader) { this.metadataReader = metadataReader; } public XmlaOlap4jMember lookupMemberByUniqueName( String memberUniqueName) throws OlapException { return metadataReader.lookupMemberByUniqueName(memberUniqueName); } public void lookupMembersByUniqueName( List memberUniqueNames, Map memberMap) throws OlapException { metadataReader.lookupMembersByUniqueName( memberUniqueNames, memberMap); } public void lookupMemberRelatives( Set treeOps, String memberUniqueName, List list) throws OlapException { metadataReader.lookupMemberRelatives( treeOps, memberUniqueName, list); } public List getLevelMembers( XmlaOlap4jLevel level) throws OlapException { return metadataReader.getLevelMembers(level); } } /** * Implementation of MemberReader that reads from an underlying member * reader and caches the results. * *

Caches are {@link Map}s containing * {@link java.lang.ref.SoftReference}s to cached objects, so can be * cleared when memory is in short supply. */ private static class CachingMetadataReader extends DelegatingMetadataReader { private final Map measuresMap; private final Map> memberMap = new HashMap>(); private final Map< XmlaOlap4jLevel, SoftReference>> levelMemberListMap = new HashMap< XmlaOlap4jLevel, SoftReference>>(); /** * Creates a CachingMetadataReader. * * @param metadataReader Underlying metadata reader * @param measuresMap Map of measures by unique name, inherited from the * cube and used read-only by this reader */ CachingMetadataReader( MetadataReader metadataReader, Map measuresMap) { super(metadataReader); this.measuresMap = measuresMap; } public XmlaOlap4jMember lookupMemberByUniqueName( String memberUniqueName) throws OlapException { // First, look in measures map. XmlaOlap4jMeasure measure = measuresMap.get(memberUniqueName); if (measure != null) { return measure; } // Next, look in cache. final SoftReference memberRef = memberMap.get(memberUniqueName); if (memberRef != null) { final XmlaOlap4jMember member = memberRef.get(); if (member != null) { return member; } } final XmlaOlap4jMember member = super.lookupMemberByUniqueName(memberUniqueName); if (member != null && member.getDimension().type != Dimension.Type.MEASURE) { memberMap.put( memberUniqueName, new SoftReference(member)); } return member; } public void lookupMembersByUniqueName( List memberUniqueNames, Map memberMap) throws OlapException { final ArrayList remainingMemberUniqueNames = new ArrayList(); for (String memberUniqueName : memberUniqueNames) { // First, look in measures map. XmlaOlap4jMeasure measure = measuresMap.get(memberUniqueName); if (measure != null) { memberMap.put(memberUniqueName, measure); continue; } // Next, look in cache. final SoftReference memberRef = this.memberMap.get(memberUniqueName); final XmlaOlap4jMember member; if (memberRef != null && (member = memberRef.get()) != null) { memberMap.put(memberUniqueName, member); continue; } remainingMemberUniqueNames.add(memberUniqueName); } // If any of the member names were not in the cache, look them up // by delegating. if (!remainingMemberUniqueNames.isEmpty()) { super.lookupMembersByUniqueName( remainingMemberUniqueNames, memberMap); // Add the previously missing members into the cache. for (String memberName : remainingMemberUniqueNames) { XmlaOlap4jMember member = memberMap.get(memberName); if (member != null) { if (!(member instanceof Measure) && member.getDimension().type != Dimension.Type.MEASURE) { this.memberMap.put( memberName, new SoftReference(member)); } } } } } public List getLevelMembers( XmlaOlap4jLevel level) throws OlapException { final SoftReference> memberListRef = levelMemberListMap.get(level); if (memberListRef != null) { final List memberList = memberListRef.get(); if (memberList != null) { return memberList; } } final List memberList = super.getLevelMembers(level); if (level.olap4jHierarchy.olap4jDimension.type != Dimension.Type.MEASURE) { levelMemberListMap.put( level, new SoftReference>(memberList)); } return memberList; } } /** * Implementation of MetadataReader that reads from the XMLA provider, * without caching. */ private class RawMetadataReader implements MetadataReader { public XmlaOlap4jMember lookupMemberByUniqueName( String memberUniqueName) throws OlapException { NamedList list = new NamedListImpl(); lookupMemberRelatives( Olap4jUtil.enumSetOf(Member.TreeOp.SELF), memberUniqueName, list); switch (list.size()) { case 0: return null; case 1: return list.get(0); default: String providerName = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection.getOlapDatabase().getProviderName(); if ("Microsoft Analysis Services".equals(providerName)) { return list.get(0); } throw new IllegalArgumentException( "more than one member with unique name '" + memberUniqueName + "'"); } } public void lookupMembersByUniqueName( List memberUniqueNames, Map memberMap) throws OlapException { if (olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection.getDatabase() .indexOf("Provider=Mondrian") != -1) { mondrianMembersLookup(memberUniqueNames, memberMap); } else { genericMembersLookup(memberUniqueNames, memberMap); } } /** * Looks up members; optimized for Mondrian servers. * * @param memberUniqueNames A list of the members to lookup * @param memberMap Output map of members keyed by unique name * @throws OlapException Gets thrown for communication errors */ private void mondrianMembersLookup( List memberUniqueNames, Map memberMap) throws OlapException { final XmlaOlap4jConnection.Context context = new XmlaOlap4jConnection.Context( XmlaOlap4jCube.this, null, null, null); final List memberList = new ArrayList(); olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection .populateList( memberList, context, XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, new XmlaOlap4jConnection.MemberHandler(), new Object[] { "CATALOG_NAME", olap4jSchema.olap4jCatalog.getName(), "SCHEMA_NAME", olap4jSchema.getName(), "CUBE_NAME", getName(), "MEMBER_UNIQUE_NAME", memberUniqueNames }); for (XmlaOlap4jMember member : memberList) { if (member != null) { memberMap.put(member.getUniqueName(), member); } } } /** * Looks up members. * * @param memberUniqueNames A list of the members to lookup * @param memberMap Output map of members keyed by unique name * @throws OlapException Gets thrown for communication errors */ private void genericMembersLookup( List memberUniqueNames, Map memberMap) throws OlapException { // Iterates through member names for (String currentMemberName : memberUniqueNames) { // Only lookup if it is not in the map yet if (!memberMap.containsKey(currentMemberName)) { XmlaOlap4jMember member = this.lookupMemberByUniqueName(currentMemberName); // Null members might mean calculated members if (member != null) { memberMap.put(member.getUniqueName(), member); } } } } public void lookupMemberRelatives( Set treeOps, String memberUniqueName, List list) throws OlapException { final XmlaOlap4jConnection.Context context = new XmlaOlap4jConnection.Context( XmlaOlap4jCube.this, null, null, null); int treeOpMask = 0; for (Member.TreeOp treeOp : treeOps) { treeOpMask |= treeOp.xmlaOrdinal(); } olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection .populateList( list, context, XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, new XmlaOlap4jConnection.MemberHandler(), new Object[] { "CATALOG_NAME", olap4jSchema.olap4jCatalog.getName(), "SCHEMA_NAME", olap4jSchema.getName(), "CUBE_NAME", getName(), "MEMBER_UNIQUE_NAME", memberUniqueName, "TREE_OP", String.valueOf(treeOpMask) }); } public List getLevelMembers( XmlaOlap4jLevel level) throws OlapException { assert level.olap4jHierarchy.olap4jDimension.olap4jCube == XmlaOlap4jCube.this; 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, context, XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, new XmlaOlap4jConnection.MemberHandler(), new Object[] { "CATALOG_NAME", olap4jSchema.olap4jCatalog.getName(), "SCHEMA_NAME", olap4jSchema.getName(), "CUBE_NAME", getName(), "DIMENSION_UNIQUE_NAME", level.olap4jHierarchy.olap4jDimension.getUniqueName(), "HIERARCHY_UNIQUE_NAME", level.olap4jHierarchy.getUniqueName(), "LEVEL_UNIQUE_NAME", level.getUniqueName() }); return list; } } } // End XmlaOlap4jCube.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/EmptyResultSet.java0000644000175000017500000006240711707255006023734 0ustar drazzibdrazzib/* // $Id: EmptyResultSet.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.OlapWrapper; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.*; import java.sql.Date; import java.util.*; import javax.sql.rowset.RowSetMetaDataImpl; /** * Implementation of {@link ResultSet} which returns 0 rows. * *

This class is used to implement {@link java.sql.DatabaseMetaData} * methods for querying object types where those object types never have * any instances for this particular driver.

* *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; * it is instantiated using {@link Factory#newEmptyResultSet}.

* * @author jhyde * @version $Id: EmptyResultSet.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 24, 2007 */ abstract class EmptyResultSet implements ResultSet, OlapWrapper { final XmlaOlap4jConnection olap4jConnection; private final List headerList; private final List> rowList; private int rowOrdinal = -1; private final RowSetMetaDataImpl metaData = new RowSetMetaDataImpl(); /** * Creates an EmptyResultSet. * * @param olap4jConnection Connection * @param headerList Column names * @param rowList List of row values */ EmptyResultSet( XmlaOlap4jConnection olap4jConnection, List headerList, List> rowList) { this.olap4jConnection = olap4jConnection; this.headerList = headerList; this.rowList = rowList; try { metaData.setColumnCount(headerList.size()); for (int i = 0; i < headerList.size(); i++) { metaData.setColumnName(i + 1, headerList.get(i)); } } catch (SQLException e) { throw new RuntimeException(e); } } /** * Returns the value of a given column * @param columnOrdinal 0-based ordinal * @return Value */ private Object getColumn(int columnOrdinal) { return rowList.get(rowOrdinal).get(columnOrdinal); } private Object getColumn(String columnLabel) throws SQLException { int column = headerList.indexOf(columnLabel); if (column < 0) { throw new SQLException("Column not found: " + columnLabel); } return rowList.get(rowOrdinal).get(column); } // implement ResultSet public boolean next() throws SQLException { // note that if rowOrdinal == rowList.size - 1, we move but then return // false if (rowOrdinal < rowList.size()) { ++rowOrdinal; } return rowOrdinal < rowList.size(); } public void close() throws SQLException { } public boolean wasNull() throws SQLException { throw new UnsupportedOperationException(); } public String getString(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); return o == null ? null : o.toString(); } public boolean getBoolean(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return false; } if (o instanceof Boolean) { return (Boolean) o; } else if (o instanceof String) { return Boolean.valueOf((String) o); } else { return !o.equals(0); } } private Number convertToNumber(Object o) { if (o instanceof Number) { return (Number)o; } else { return new BigDecimal(o.toString()); } } public byte getByte(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return 0; } return convertToNumber(o).byteValue(); } public short getShort(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return 0; } return convertToNumber(o).shortValue(); } public int getInt(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return 0; } return convertToNumber(o).intValue(); } public long getLong(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return 0; } return ((Number) o).longValue(); } public float getFloat(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return 0; } return convertToNumber(o).floatValue(); } public double getDouble(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return 0; } return convertToNumber(o).doubleValue(); } public BigDecimal getBigDecimal( int columnIndex, int scale) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return null; } BigDecimal bd; if (o instanceof BigDecimal) { bd = (BigDecimal)o; } else { bd = new BigDecimal(o.toString()); } if (bd.scale() != scale) { bd = bd.setScale(scale); } return bd; } public byte[] getBytes(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); return (byte[]) o; } public Date getDate(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); return (Date) o; } public Time getTime(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); return (Time) o; } public Timestamp getTimestamp(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); return (Timestamp) o; } public InputStream getAsciiStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getUnicodeStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getBinaryStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public String getString(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); return o == null ? null : o.toString(); } public boolean getBoolean(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o instanceof Boolean) { return (Boolean) o; } else if (o instanceof String) { return Boolean.valueOf((String) o); } else { return !o.equals(0); } } public byte getByte(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return 0; } return convertToNumber(o).byteValue(); } public short getShort(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return 0; } return convertToNumber(o).shortValue(); } public int getInt(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return 0; } return convertToNumber(o).intValue(); } public long getLong(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return 0; } return convertToNumber(o).longValue(); } public float getFloat(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return 0; } return convertToNumber(o).floatValue(); } public double getDouble(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return 0; } return convertToNumber(o).doubleValue(); } public BigDecimal getBigDecimal( String columnLabel, int scale) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return null; } BigDecimal bd; if (o instanceof BigDecimal) { bd = (BigDecimal)o; } else { bd = new BigDecimal(o.toString()); } if (bd.scale() != scale) { bd = bd.setScale(scale); } return bd; } public byte[] getBytes(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); return (byte[]) o; } public Date getDate(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); return (Date) o; } public Time getTime(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); return (Time) o; } public Timestamp getTimestamp(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); return (Timestamp) o; } public InputStream getAsciiStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getUnicodeStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getBinaryStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public SQLWarning getWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void clearWarnings() throws SQLException { throw new UnsupportedOperationException(); } public String getCursorName() throws SQLException { throw new UnsupportedOperationException(); } public ResultSetMetaData getMetaData() throws SQLException { return metaData; } public Object getObject(int columnIndex) throws SQLException { return getColumn(columnIndex - 1); } public Object getObject(String columnLabel) throws SQLException { return getColumn(columnLabel); } public int findColumn(String columnLabel) throws SQLException { int column = headerList.indexOf(columnLabel); if (column < 0) { throw new SQLException("Column not found: " + columnLabel); } return column; } public Reader getCharacterStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Reader getCharacterStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal(int columnIndex) throws SQLException { Object o = getColumn(columnIndex - 1); if (o == null) { return null; } BigDecimal bd; if (o instanceof BigDecimal) { bd = (BigDecimal)o; } else { bd = new BigDecimal(o.toString()); } return bd; } public BigDecimal getBigDecimal(String columnLabel) throws SQLException { Object o = getColumn(columnLabel); if (o == null) { return null; } BigDecimal bd; if (o instanceof BigDecimal) { bd = (BigDecimal)o; } else { bd = new BigDecimal(o.toString()); } return bd; } public boolean isBeforeFirst() throws SQLException { return rowOrdinal < 0; } public boolean isAfterLast() throws SQLException { return rowOrdinal >= rowList.size(); } public boolean isFirst() throws SQLException { return rowOrdinal == 0; } public boolean isLast() throws SQLException { return rowOrdinal == rowList.size() - 1; } public void beforeFirst() throws SQLException { rowOrdinal = -1; } public void afterLast() throws SQLException { rowOrdinal = rowList.size(); } public boolean first() throws SQLException { if (rowList.size() == 0) { return false; } else { rowOrdinal = 0; return true; } } public boolean last() throws SQLException { if (rowList.size() == 0) { return false; } else { rowOrdinal = rowList.size() - 1; return true; } } public int getRow() throws SQLException { return rowOrdinal + 1; // 1-based } public boolean absolute(int row) throws SQLException { int newRowOrdinal = row - 1;// convert to 0-based if (newRowOrdinal >= 0 && newRowOrdinal < rowList.size()) { rowOrdinal = newRowOrdinal; return true; } else { return false; } } public boolean relative(int rows) throws SQLException { int newRowOrdinal = rowOrdinal + (rows - 1); if (newRowOrdinal >= 0 && newRowOrdinal < rowList.size()) { rowOrdinal = newRowOrdinal; return true; } else { return false; } } public boolean previous() throws SQLException { // converse of next(); note that if rowOrdinal == 0, we decrement // but return false if (rowOrdinal >= 0) { --rowOrdinal; } return rowOrdinal >= 0; } public void setFetchDirection(int direction) throws SQLException { throw new UnsupportedOperationException(); } public int getFetchDirection() throws SQLException { throw new UnsupportedOperationException(); } public void setFetchSize(int rows) throws SQLException { throw new UnsupportedOperationException(); } public int getFetchSize() throws SQLException { throw new UnsupportedOperationException(); } public int getType() throws SQLException { throw new UnsupportedOperationException(); } public int getConcurrency() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowUpdated() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowInserted() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowDeleted() throws SQLException { throw new UnsupportedOperationException(); } public void updateNull(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public void updateBoolean(int columnIndex, boolean x) throws SQLException { throw new UnsupportedOperationException(); } public void updateByte(int columnIndex, byte x) throws SQLException { throw new UnsupportedOperationException(); } public void updateShort(int columnIndex, short x) throws SQLException { throw new UnsupportedOperationException(); } public void updateInt(int columnIndex, int x) throws SQLException { throw new UnsupportedOperationException(); } public void updateLong(int columnIndex, long x) throws SQLException { throw new UnsupportedOperationException(); } public void updateFloat(int columnIndex, float x) throws SQLException { throw new UnsupportedOperationException(); } public void updateDouble(int columnIndex, double x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBigDecimal( int columnIndex, BigDecimal x) throws SQLException { throw new UnsupportedOperationException(); } public void updateString(int columnIndex, String x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBytes(int columnIndex, byte x[]) throws SQLException { throw new UnsupportedOperationException(); } public void updateDate(int columnIndex, Date x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTime(int columnIndex, Time x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTimestamp( int columnIndex, Timestamp x) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( int columnIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( int columnIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( int columnIndex, Reader x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject( int columnIndex, Object x, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(int columnIndex, Object x) throws SQLException { throw new UnsupportedOperationException(); } public void updateNull(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateBoolean( String columnLabel, boolean x) throws SQLException { throw new UnsupportedOperationException(); } public void updateByte(String columnLabel, byte x) throws SQLException { throw new UnsupportedOperationException(); } public void updateShort(String columnLabel, short x) throws SQLException { throw new UnsupportedOperationException(); } public void updateInt(String columnLabel, int x) throws SQLException { throw new UnsupportedOperationException(); } public void updateLong(String columnLabel, long x) throws SQLException { throw new UnsupportedOperationException(); } public void updateFloat(String columnLabel, float x) throws SQLException { throw new UnsupportedOperationException(); } public void updateDouble(String columnLabel, double x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBigDecimal( String columnLabel, BigDecimal x) throws SQLException { throw new UnsupportedOperationException(); } public void updateString(String columnLabel, String x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBytes(String columnLabel, byte x[]) throws SQLException { throw new UnsupportedOperationException(); } public void updateDate(String columnLabel, Date x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTime(String columnLabel, Time x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTimestamp( String columnLabel, Timestamp x) throws SQLException { throw new UnsupportedOperationException(); } public void updateAsciiStream( String columnLabel, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBinaryStream( String columnLabel, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateCharacterStream( String columnLabel, Reader reader, int length) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject( String columnLabel, Object x, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(String columnLabel, Object x) throws SQLException { throw new UnsupportedOperationException(); } public void insertRow() throws SQLException { throw new UnsupportedOperationException(); } public void updateRow() throws SQLException { throw new UnsupportedOperationException(); } public void deleteRow() throws SQLException { throw new UnsupportedOperationException(); } public void refreshRow() throws SQLException { throw new UnsupportedOperationException(); } public void cancelRowUpdates() throws SQLException { throw new UnsupportedOperationException(); } public void moveToInsertRow() throws SQLException { throw new UnsupportedOperationException(); } public void moveToCurrentRow() throws SQLException { throw new UnsupportedOperationException(); } public Statement getStatement() throws SQLException { throw new UnsupportedOperationException(); } public Object getObject( int columnIndex, Map> map) throws SQLException { throw new UnsupportedOperationException(); } public Ref getRef(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Blob getBlob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Clob getClob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Array getArray(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Object getObject( String columnLabel, Map> map) throws SQLException { throw new UnsupportedOperationException(); } public Ref getRef(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Blob getBlob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Clob getClob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Array getArray(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(int columnIndex, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(int columnIndex, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp( int columnIndex, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp( String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public URL getURL(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public URL getURL(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateRef(int columnIndex, Ref x) throws SQLException { throw new UnsupportedOperationException(); } public void updateRef(String columnLabel, Ref x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(int columnIndex, Blob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(String columnLabel, Blob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(int columnIndex, Clob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(String columnLabel, Clob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateArray(int columnIndex, Array x) throws SQLException { throw new UnsupportedOperationException(); } public void updateArray(String columnLabel, Array x) throws SQLException { throw new UnsupportedOperationException(); } // implement Wrapper public T unwrap(Class iface) throws SQLException { if (iface.isInstance(this)) { return iface.cast(this); } throw olap4jConnection.helper.createException("cannot cast"); } public boolean isWrapperFor(Class iface) throws SQLException { return iface.isInstance(this); } } // End EmptyResultSet.java olap4j-1.0.1.500/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMetaData.java0000644000175000017500000001652411707255006025612 0ustar drazzibdrazzib/* // $Id: XmlaOlap4jCellSetMetaData.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.xmla; import org.olap4j.CellSetAxisMetaData; import org.olap4j.CellSetMetaData; import org.olap4j.impl.ArrayNamedListImpl; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; import java.sql.SQLException; import java.util.*; /** * Implementation of {@link org.olap4j.CellSetMetaData} * for XML/A providers. * * @author jhyde * @version $Id: XmlaOlap4jCellSetMetaData.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 13, 2007 */ class XmlaOlap4jCellSetMetaData implements CellSetMetaData { final XmlaOlap4jCube cube; private final NamedList axisMetaDataList = new ArrayNamedListImpl() { protected String getName(CellSetAxisMetaData axisMetaData) { return axisMetaData.getAxisOrdinal().name(); } }; private final XmlaOlap4jCellSetAxisMetaData filterAxisMetaData; private final NamedList cellProperties = new ArrayNamedListImpl() { protected String getName(Property property) { return property.getName(); } }; final Map propertiesByTag; XmlaOlap4jCellSetMetaData( XmlaOlap4jStatement olap4jStatement, XmlaOlap4jCube cube, XmlaOlap4jCellSetAxisMetaData filterAxisMetaData, List axisMetaDataList, List cellProperties) { assert olap4jStatement != null; assert cube != null; assert filterAxisMetaData != null; this.cube = cube; this.filterAxisMetaData = filterAxisMetaData; this.axisMetaDataList.addAll(axisMetaDataList); this.propertiesByTag = new HashMap(); for (XmlaOlap4jCellProperty cellProperty : cellProperties) { Property property; try { property = Property.StandardCellProperty.valueOf( cellProperty.propertyName); this.propertiesByTag.put(cellProperty.tag, property); } catch (IllegalArgumentException e) { property = cellProperty; this.propertiesByTag.put(property.getName(), property); } this.cellProperties.add(property); } } private XmlaOlap4jCellSetMetaData( XmlaOlap4jStatement olap4jStatement, XmlaOlap4jCube cube, XmlaOlap4jCellSetAxisMetaData filterAxisMetaData, List axisMetaDataList, Map propertiesByTag, List cellProperties) { assert olap4jStatement != null; assert cube != null; assert filterAxisMetaData != null; this.cube = cube; this.filterAxisMetaData = filterAxisMetaData; this.axisMetaDataList.addAll(axisMetaDataList); this.propertiesByTag = propertiesByTag; this.cellProperties.addAll(cellProperties); } XmlaOlap4jCellSetMetaData cloneFor( XmlaOlap4jPreparedStatement preparedStatement) { return new XmlaOlap4jCellSetMetaData( preparedStatement, cube, filterAxisMetaData, axisMetaDataList, propertiesByTag, cellProperties); } // implement CellSetMetaData public NamedList getCellProperties() { return Olap4jUtil.cast(cellProperties); } public Cube getCube() { return cube; } public NamedList getAxesMetaData() { return axisMetaDataList; } public CellSetAxisMetaData getFilterAxisMetaData() { return filterAxisMetaData; } // implement ResultSetMetaData public int getColumnCount() throws SQLException { throw new UnsupportedOperationException(); } public boolean isAutoIncrement(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isCaseSensitive(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isSearchable(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isCurrency(int column) throws SQLException { throw new UnsupportedOperationException(); } public int isNullable(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isSigned(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getColumnDisplaySize(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getColumnLabel(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getColumnName(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getSchemaName(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getPrecision(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getScale(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getTableName(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getCatalogName(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getColumnType(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getColumnTypeName(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isReadOnly(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isWritable(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isDefinitelyWritable(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getColumnClassName(int column) throws SQLException { throw new UnsupportedOperationException(); } // implement Wrapper public T unwrap(Class iface) throws SQLException { throw new UnsupportedOperationException(); } public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException(); } } // End XmlaOlap4jCellSetMetaData.java olap4j-1.0.1.500/src/org/olap4j/AllocationPolicy.java0000644000175000017500000000774511707255012021775 0ustar drazzibdrazzib/* // $Id: AllocationPolicy.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; /** * Enumeration of the policies that can be used to modify the values of * child cells when their parent cell is modified in a writeback operation. * * @see Cell#setValue * * @author jhyde * @version $Id: AllocationPolicy.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public enum AllocationPolicy { /** * Every atomic cell that contributes to the updated cell will be * assigned an equal value that is: * *
* <atomic cell value> = * <value> / Count(atomic cells contained in <tuple>) *
*/ EQUAL_ALLOCATION, /** * Every atomic cell that contributes to the updated cell will be * changed according to: * *
* <atomic cell value> = <atomic cell value> + * (<value> - <existing value>) / * Count(atomic cells contained in <tuple>) *
*/ EQUAL_INCREMENT, /** * Every atomic cell that contributes to the updated cell will be * assigned an equal value that is: * *
* <atomic cell value> = * <value> * <weight value expression> *
* *

Takes an optional argument, {@code weight_value_expression}. * If {@code weight_value_expression} is not provided, the following * expression is assigned to it by default: * *

* <weight value expression> = * <atomic cell value> / <existing value> *
* *

The value of {@code weight value expression} should be expressed * as a value between 0 and 1. This value specifies the ratio of the * allocated value you want to assign to the atomic cells that are * affected by the allocation. It is the client application programmer's * responsibilffity to create expressions whose rollup aggregate values * will equal the allocated value of the expression. */ WEIGHTED_ALLOCATION, /** * Every atomic cell that contributes to the updated cell will be * changed according to: * *

* <atomic cell value> = <atomic cell value> + * (<value> - <existing value>) * * <weight value expression> *
* *

Takes an optional argument, {@code weight_value_expression}. * If {@code weight_value_expression} is not provided, the following * expression is assigned to it by default: * *

* <weight value expression> = * <atomic cell value> / <existing value> *
* *

The value of {@code weight value expression} should be expressed * as a value between 0 and 1. This value specifies the ratio of the * allocated value you want to assign to the atomic cells that are * affected by the allocation. It is the client application programmer's * responsibility to create expressions whose rollup aggregate values * will equal the allocated value of the expression. */ WEIGHTED_INCREMENT, } // End AllocationPolicy.java olap4j-1.0.1.500/src/org/olap4j/OlapDatabaseMetaData.java0000644000175000017500000013036611707255012022445 0ustar drazzibdrazzib/* // $Id: OlapDatabaseMetaData.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.metadata.Member; import java.sql.*; import java.util.Set; /** * Information about an OLAP database. * *

Methods are provided to query the metadata catalog of the database. * There is a method for each metadata class, and each method takes zero or more * parameters to qualify the instances should be returned, and returns a JDBC * {@link java.sql.ResultSet}. * *

For example, {@link #getCubes} returns the description of a cube. * * @author jhyde * @version $Id: OlapDatabaseMetaData.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 12, 2006 */ public interface OlapDatabaseMetaData extends DatabaseMetaData, OlapWrapper { // override return type /** * {@inheritDoc} */ OlapConnection getConnection() throws SQLException; /** * Returns the granularity of changes to cell sets that the database is * capable of providing. * *

It's optional whether an olap4j provider supports cellset listeners, * and also optional which granularities it supports. If the provider does * not support the cell set listener API, returns an empty set. Never * returns null. * * @return set of the granularities that are supported when listening for * changes to a cell set, never null */ Set getSupportedCellSetListenerGranularities() throws OlapException; /** * Retrieves a result set describing the Actions in this database. * *

Specification as for XML/A MDSCHEMA_ACTIONS schema rowset. * *

Each action description has the following columns: *

  • CATALOG_NAME String (may be null) => The name of * the database.
  • *
  • SCHEMA_NAME String (may be null) => The name of * the schema to which this action belongs.
  • *
  • CUBE_NAME String => The name of the cube to which this action * belongs.
  • *
  • ACTION_NAME String => The name of the action.
  • *
  • COORDINATE String => null
  • *
  • COORDINATE_TYPE int => null
  • * * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema name * as it is stored in the database; "" retrieves those without a * schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube (such as shared dimensions); * null means that the cube name should * not be used to narrow the search * * @param actionNamePattern an action name pattern; must match the * action name as it is stored in the database; null * means that the action name should not be used to narrow the * search * * @return a ResultSet object in which each row is an * action description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape */ ResultSet getActions( String catalog, String schemaPattern, String cubeNamePattern, String actionNamePattern) throws OlapException; /** * Retrieves a row set describing the databases that are available on the * server. * *

    Specification as for XML/A DISCOVER_DATASOURCES schema rowset. * *

      *
    1. DATA_SOURCE_NAME String => The name of the data source, such * as FoodMart 2000.
    2. *
    3. DATA_SOURCE_DESCRIPTION String => A description of the data * source, as entered by the publisher. (may be * null)
    4. *
    5. URL String => The unique path that shows where to invoke the * XML for Analysis methods for that data source. (may be * null)
    6. *
    7. DATA_SOURCE_INFO String => A string containing any additional * information required to connect to the data source. This can * include the Initial Catalog property or other information for * the provider.
      Example: "Provider=MSOLAP;Data * Source=Local;" (may be null)
    8. *
    9. PROVIDER_NAME String => The name of the provider behind the * data source.
      Example: "MSDASQL" (may be * null)
    10. *
    11. PROVIDER_TYPE EnumerationArray => The types of data supported * by the provider. May include one or more of the following * types. Example follows this table.
      TDP: tabular data * provider.
      MDP: multidimensional data provider.
      DMP: * data mining provider. A DMP provider implements the OLE DB for * Data Mining specification.
    12. *
    13. AUTHENTICATION_MODE EnumString => Specification of what type * of security mode the data source uses. Values can be one of * the following:
      Unauthenticated: no user ID or password * needs to be sent.
      Authenticated: User ID and Password must * be included in the information required for the * connection.
      Integrated: the data source uses the * underlying security to determine authorization, such as * Integrated Security provided by Microsoft Internet Information * Services (IIS).
    14. *
    * * @return a ResultSet object in which each row is an * OLAP database description * @throws OlapException if a database access error occurs */ ResultSet getDatabases() throws OlapException; /** * Retrieves a list of information on supported literals, including data * types and values. * *

    Specification as for XML/A DISCOVER_LITERALS schema rowset. * *

      *
    1. LITERAL_NAME String => The name of the literal described in * the row.
      Example: DBLITERAL_LIKE_PERCENT
    2. *
    3. LITERAL_VALUE String (may be null) => Contains * the actual literal value.
      Example, if LiteralName is * DBLITERAL_LIKE_PERCENT and the percent character (%) is used * to match zero or more characters in a LIKE clause, this * column's value would be "%".
    4. *
    5. LITERAL_INVALID_CHARS String (may be null) => * The characters, in the literal, that are not valid.
      For * example, if table names can contain anything other than a * numeric character, this string would be "0123456789".
    6. *
    7. LITERAL_INVALID_STARTING_CHARS String (may be * null) => The characters that are not valid as the * first character of the literal. If the literal can start with * any valid character, this is null.
    8. *
    9. LITERAL_MAX_LENGTH int (may be null) => The * maximum number of characters in the literal. If there is no * maximum or the maximum is unknown, the value is -1.
    10. *
    * * @return a ResultSet object in which each row is a * literal description * * @exception OlapException if a database access error occurs */ ResultSet getLiterals() throws OlapException; /** * Retrieves a list of the standard and provider-specific properties * supported by an olap4j provider. Properties that are not supported by a * provider are not listed in the return result set. * *

    Specification as for XML/A DISCOVER_PROPERTIES schema rowset. * *

    Not to be confused with {@link #getProperties}. * *

      *
    1. PROPERTY_NAME String => The name of the property.
    2. *
    3. PROPERTY_DESCRIPTION String => A localizable text description * of the property.
    4. *
    5. PROPERTY_TYPE String => The XML data type of the * property.
    6. *
    7. PROPERTY_ACCESS_TYPE EnumString => Access for the property. * The value can be Read, Write, or ReadWrite.
    8. *
    9. IS_REQUIRED Boolean => True if a property is required, false * if it is not required.
    10. *
    11. PROPERTY_VALUE String => The current value of the * property.
    12. *
    * * @param dataSourceName Name of data source * * @param propertyNamePattern an property name pattern; must match the * property name as it is stored in the database; null * means that the property name should not be used to narrow the * search * * @return a ResultSet object in which each row is a * the description of a database property * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape */ ResultSet getDatabaseProperties( String dataSourceName, String propertyNamePattern) throws OlapException; /** * Retrieves a result set describing member and cell Properties. * *

    Specification as for XML/A MDSCHEMA_PROPERTIES schema rowset. * *

    Not to be confused with {@link #getDatabaseProperties(String,String)}. * *

  • CATALOG_NAME String (may be null) => The name of * the database.
  • *
  • SCHEMA_NAME String (may be null) => The name of * the schema to which this property belongs.
  • *
  • CUBE_NAME String => The name of the cube.
  • *
  • DIMENSION_UNIQUE_NAME String => The unique name of the * dimension.
  • *
  • HIERARCHY_UNIQUE_NAME String => The unique name of the * hierarchy.
  • *
  • LEVEL_UNIQUE_NAME String => The unique name of the level to * which this property belongs.
  • *
  • MEMBER_UNIQUE_NAME String (may be null) => The * unique name of the member to which the property belongs.
  • *
  • PROPERTY_NAME String => Name of the property.
  • *
  • PROPERTY_CAPTION String => A label or caption associated with * the property, used primarily for display purposes.
  • *
  • PROPERTY_TYPE Short => A bitmap that specifies the type of * the property
  • *
  • DATA_TYPE UnsignedShort => Data type of the property.
  • *
  • PROPERTY_CONTENT_TYPE Short (may be null) => The * type of the property.
  • *
  • DESCRIPTION String (may be null) => A * human-readable description of the measure.
  • * * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema * name as it is stored in the database; "" retrieves those without * a schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube; null means that the cube name should * not be used to narrow the search * * @param dimensionUniqueName unique name of a dimension (not a pattern); * must match the dimension name as it is stored in the database; * null means that the dimension name should not be * used to narrow the search * * @param hierarchyUniqueName unique name of a hierarchy (not a pattern); * must match the * hierarchy name as it is stored in the database; null * means that the hierarchy name should not be used to narrow the * search * * @param levelUniqueName unique name of a level (not a pattern); * must match the * level name as it is stored in the database; null * means that the level name should not be used to narrow the * search * * @param memberUniqueName unique name of member (not a pattern); * null * means that the member unique name should not be used to narrow * the search * * @param propertyNamePattern a property name pattern; must match the * property name as it is stored in the database; null * means that the property name should not be used to narrow the * search * * @return a ResultSet object in which each row is a * description of a member or cell property * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.Property */ ResultSet getProperties( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelUniqueName, String memberUniqueName, String propertyNamePattern) throws OlapException; /** * Retrieves a comma-separated list of all of this database's MDX keywords. * * @return the list of this database's MDX keywords * * @exception OlapException if a database access error occurs */ String getMdxKeywords() throws OlapException; /** * Retrieves a result set describing the Cubes in this database. * *

    Specification as for XML/A MDSCHEMA_CUBES schema rowset. * *

    Each cube description has the following columns: *

      *
    1. CATALOG_NAME String (may be null) => The name of * the catalog to which this cube belongs.
    2. *
    3. SCHEMA_NAME String (may be null) => The name of * the schema to which this cube belongs.
    4. *
    5. CUBE_NAME String => Name of the cube.
    6. *
    7. CUBE_TYPE String => Cube type.
    8. *
    9. CUBE_GUID UUID (may be null) => Cube type.
    10. *
    11. CREATED_ON Timestamp (may be null) => Date and * time of cube creation.
    12. *
    13. LAST_SCHEMA_UPDATE Timestamp (may be null) => * Date and time of last schema update.
    14. *
    15. SCHEMA_UPDATED_BY String (may be null) => User * ID of the person who last updated the schema.
    16. *
    17. LAST_DATA_UPDATE Timestamp (may be null) => Date * and time of last data update.
    18. *
    19. DATA_UPDATED_BY String (may be null) => User ID * of the person who last updated the data.
    20. *
    21. IS_DRILLTHROUGH_ENABLED boolean => Describes whether * DRILLTHROUGH can be performed on the members of a cube
    22. *
    23. IS_WRITE_ENABLED boolean => Describes whether a cube is * write-enabled
    24. *
    25. IS_LINKABLE boolean => Describes whether a cube can be used * in a linked cube
    26. *
    27. IS_SQL_ENABLED boolean => Describes whether or not SQL can be * used on the cube
    28. *
    29. DESCRIPTION String (may be null) => A * user-friendly description of the cube.
    30. *
    31. CUBE_CAPTION String (may be null) => * The caption of the cube.
    32. *
    33. BASE_CUBE_NAME String (may be null) => * The name of the source cube if this cube is a perspective * cube.
    34. *
    * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema * name as it is stored in the database; "" retrieves those without * a schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; null * means that the cube name should not be used to narrow the search * * @return ResultSet in which each row is a cube description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.Cube */ public ResultSet getCubes( String catalog, String schemaPattern, String cubeNamePattern) throws OlapException; /** * Retrieves a result set describing the shared and private Dimensions * in this database. * *

    Specification as for XML/A MDSCHEMA_DIMENSIONS schema rowset. * *

    Each dimension description has the following columns: *

      *
    1. CATALOG_NAME String (may be null) => The name of * the database.
    2. *
    3. SCHEMA_NAME String (may be null) => Not * supported.
    4. *
    5. CUBE_NAME String => The name of the cube.
    6. *
    7. DIMENSION_NAME String => The name of the dimension.
    8. *
    9. DIMENSION_UNIQUE_NAME String => The unique name of the * dimension.
    10. *
    11. DIMENSION_GUID String (may be null) => Not * supported.
    12. *
    13. DIMENSION_CAPTION String => The caption of the * dimension.
    14. *
    15. DIMENSION_ORDINAL int => The position of the dimension within * the cube.
    16. *
    17. DIMENSION_TYPE Short => The type of the dimension.
    18. *
    19. DIMENSION_CARDINALITY int => The number of members in the key * attribute.
    20. *
    21. DEFAULT_HIERARCHY String => A hierarchy from the dimension. * Preserved for backwards compatibility.
    22. *
    23. DESCRIPTION String (may be null) => A * user-friendly description of the dimension.
    24. *
    25. IS_VIRTUAL boolean (may be null) => Always * FALSE.
    26. *
    27. IS_READWRITE boolean (may be null) => A Boolean * that indicates whether the dimension is write-enabled.
    28. *
    29. DIMENSION_UNIQUE_SETTINGS int (may be null) => A * bitmap that specifies which columns contain unique values if * the dimension contains only members with unique names.
    30. *
    31. DIMENSION_MASTER_UNIQUE_NAME String (may be * null) => Always NULL.
    32. *
    33. DIMENSION_IS_VISIBLE boolean (may be null) => * Always TRUE.
    34. *
    * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema name * as it is stored in the database; "" retrieves those without a * schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube (such as shared dimensions); * null means that the cube name should * not be used to narrow the search * * @param dimensionNamePattern a dimension name pattern; must match the * dimension name as it is stored in the database; null * means that the dimension name should not be used to narrow the * search * * @return a ResultSet object in which each row is a * dimension description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.Dimension */ ResultSet getDimensions( String catalog, String schemaPattern, String cubeNamePattern, String dimensionNamePattern) throws OlapException; /** * Retrieves a result set describing the Functions available to client * applications connected to the database. * *

    Specification as for XML/A MDSCHEMA_FUNCTIONS schema rowset. * *

    Each function description has the following columns: *

  • FUNCTION_NAME String => The name of the function.
  • *
  • DESCRIPTION String (may be null) => A * description of the function.
  • *
  • PARAMETER_LIST String (may be null) => A comma * delimited list of parameters.
  • *
  • RETURN_TYPE int => The VARTYPE of the return data type of the * function.
  • *
  • ORIGIN int => The origin of the function: 1 for MDX * functions. 2 for user-defined functions.
  • *
  • INTERFACE_NAME String => The name of the interface for * user-defined functions
  • *
  • LIBRARY_NAME String (may be null) => The name of * the type library for user-defined functions. NULL for MDX * functions.
  • *
  • CAPTION String (may be null) => The display * caption for the function.
  • * * * @param functionNamePattern a function name pattern; must match the * function name as it is stored in the database; null * means that the function name should not be used to narrow the * search * * @return a ResultSet object in which each row is a * function description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape */ // NOTE: '#getFunctions(String, String, String)' above generates a javadoc // error on JDK 1.5, because it is new in JDBC 4.0/JDK 1.6. But please leave // it in. Most olap4j users run on JDK 1.6 or later, and the javadoc is // intended for them. ResultSet getOlapFunctions( String functionNamePattern) throws OlapException; /** * Retrieves a result set describing the Hierarchies in this database. * *

    Specification as for XML/A MDSCHEMA_HIERARCHIES schema rowset. * *

    Each hierarchy description has the following columns: *

  • CATALOG_NAME String (may be null) => The name of * the catalog to which this hierarchy belongs.
  • *
  • SCHEMA_NAME String (may be null) => Not * supported
  • *
  • CUBE_NAME String => The name of the cube to which this * hierarchy belongs.
  • *
  • DIMENSION_UNIQUE_NAME String => The unique name of the * dimension to which this hierarchy belongs.
  • *
  • HIERARCHY_NAME String => The name of the hierarchy. Blank if * there is only a single hierarchy in the dimension.
  • *
  • HIERARCHY_UNIQUE_NAME String => The unique name of the * hierarchy.
  • *
  • HIERARCHY_GUID String (may be null) => Hierarchy * GUID.
  • *
  • HIERARCHY_CAPTION String => A label or a caption associated * with the hierarchy.
  • *
  • DIMENSION_TYPE Short => The type of the dimension.
  • *
  • HIERARCHY_CARDINALITY int => The number of members in the * hierarchy.
  • *
  • DEFAULT_MEMBER String (may be null) => The * default member for this hierarchy.
  • *
  • ALL_MEMBER String (may be null) => The member at * the highest level of rollup in the hierarchy.
  • *
  • DESCRIPTION String (may be null) => A * human-readable description of the hierarchy. NULL if no * description exists.
  • *
  • STRUCTURE Short => The structure of the hierarchy.
  • *
  • IS_VIRTUAL boolean => Always returns False.
  • *
  • IS_READWRITE boolean => A Boolean that indicates whether the * Write Back to dimension column is enabled.
  • *
  • DIMENSION_UNIQUE_SETTINGS int => Always returns * MDDIMENSIONS_MEMBER_KEY_UNIQUE (1).
  • *
  • DIMENSION_IS_VISIBLE boolean => Always returns true.
  • *
  • HIERARCHY_ORDINAL int => The ordinal number of the hierarchy * across all hierarchies of the cube.
  • *
  • DIMENSION_IS_SHARED boolean => Always returns true.
  • *
  • PARENT_CHILD boolean (may be null) => Is * hierarchy a parent.
  • * * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema name * as it is stored in the database; "" retrieves those without a * schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube; null means that the cube name should * not be used to narrow the search * * @param dimensionUniqueName unique name of a dimension (not a pattern); * must match the * dimension name as it is stored in the database; null * means that the dimension name should not be used to narrow the * search * * @param hierarchyNamePattern a hierarchy name pattern; must match the * hierarchy name as it is stored in the database; null * means that the hierarchy name should not be used to narrow the * search * * @return a ResultSet object in which each row is a * hierarchy description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.Hierarchy */ ResultSet getHierarchies( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyNamePattern) throws OlapException; /** * Retrieves a result set describing the Levels in this database. * *

    Specification as for XML/A MDSCHEMA_LEVELS schema rowset. * *

    Each level description has the following columns: *

      *
    1. CATALOG_NAME String (may be null) => The name of * the catalog to which this level belongs.
    2. *
    3. SCHEMA_NAME String (may be null) => The name of * the schema to which this level belongs.
    4. *
    5. CUBE_NAME String => The name of the cube to which this level * belongs.
    6. *
    7. DIMENSION_UNIQUE_NAME String => The unique name of the * dimension to which this level belongs.
    8. *
    9. HIERARCHY_UNIQUE_NAME String => The unique name of the * hierarchy.
    10. *
    11. LEVEL_NAME String => The name of the level.
    12. *
    13. LEVEL_UNIQUE_NAME String => The properly escaped unique name * of the level.
    14. *
    15. LEVEL_GUID String (may be null) => Level * GUID.
    16. *
    17. LEVEL_CAPTION String => A label or caption associated with * the hierarchy.
    18. *
    19. LEVEL_NUMBER int => The distance of the level from the root * of the hierarchy. Root level is zero (0).
    20. *
    21. LEVEL_CARDINALITY int => The number of members in the level. * This value can be an approximation of the real * cardinality.
    22. *
    23. LEVEL_TYPE int => Type of the level
    24. *
    25. CUSTOM_ROLLUP_SETTINGS int => A bitmap that specifies the * custom rollup options.
    26. *
    27. LEVEL_UNIQUE_SETTINGS int => A bitmap that specifies which * columns contain unique values, if the level only has members * with unique names or keys.
    28. *
    29. LEVEL_IS_VISIBLE boolean => A Boolean that indicates whether * the level is visible.
    30. *
    31. DESCRIPTION String (may be null) => A * human-readable description of the level. NULL if no * description exists.
    32. *
    * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema name * as it is stored in the database; "" retrieves those without a * schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube; null means that the cube name should * not be used to narrow the search * * @param dimensionUniqueName unique name of a dimension (not a pattern); * must match the * dimension name as it is stored in the database; null * means that the dimension name should not be used to narrow the * search * * @param hierarchyUniqueName unique name of a hierarchy (not a pattern); * must match the * hierarchy name as it is stored in the database; null * means that the hierarchy name should not be used to narrow the * search * * @param levelNamePattern a level name pattern; must match the * level name as it is stored in the database; null * means that the level name should not be used to narrow the * search * * @return a ResultSet object in which each row is a * level description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.Level */ ResultSet getLevels( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelNamePattern) throws OlapException; /** * Retrieves a result set describing the Measures in this database. * *

    Specification as for XML/A MDSCHEMA_MEASURES schema rowset. * *

    Each measure description has the following columns: *

      *
    1. CATALOG_NAME String (may be null) => The name of * the catalog to which this measure belongs.
    2. *
    3. SCHEMA_NAME String (may be null) => The name of * the schema to which this measure belongs.
    4. *
    5. CUBE_NAME String => The name of the cube to which this * measure belongs.
    6. *
    7. MEASURE_NAME String => The name of the measure.
    8. *
    9. MEASURE_UNIQUE_NAME String => The Unique name of the * measure.
    10. *
    11. MEASURE_CAPTION String => A label or caption associated with * the measure.
    12. *
    13. MEASURE_GUID String (may be null) => Measure * GUID.
    14. *
    15. MEASURE_AGGREGATOR int => How a measure was derived.
    16. *
    17. DATA_TYPE UnsignedShort => Data type of the measure.
    18. *
    19. MEASURE_IS_VISIBLE boolean => A Boolean that always returns * True. If the measure is not visible, it will not be included * in the schema rowset.
    20. *
    21. LEVELS_LIST String (may be null) => A string * that always returns NULL. EXCEPT that SQL Server returns * non-null values!!!
    22. *
    23. DESCRIPTION String (may be null) => A * human-readable description of the measure.
    24. *
    * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema name * as it is stored in the database; "" retrieves those without a * schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube; null means that the cube name should * not be used to narrow the search * * @param measureNamePattern a measure name pattern; must match the * measure name as it is stored in the database; null * means that the measure name should not be used to narrow the * search * * @param measureUniqueName unique name of measure (not a pattern); * null means that the measure unique name should not * be used to narrow the search * * @return a ResultSet object in which each row is a * measure description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.Measure */ ResultSet getMeasures( String catalog, String schemaPattern, String cubeNamePattern, String measureNamePattern, String measureUniqueName) throws OlapException; /** * Retrieves a result set describing the Members in this database. * *

    Specification as for XML/A MDSCHEMA_MEMBERS schema rowset. Rows * are sorted by level number then by ordinal. * *

    The treeOps parameter allows you to retrieve members * relative to a given member. It is only applicable if a * memberUniqueName is also specified; otherwise it is * ignored. The following example retrieves all descendants and ancestors * of California, but not California itself: * *

    *
         * OlapDatabaseMetaData metaData;
         * ResultSet rset = metaData.getMembers(
         *     "LOCALDB", "FoodMart", "Sales", null, null, null,
         *     "[Customers].[USA].[CA]",
         *     EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.DESCENDANTS));
         * 
    *
    * *

    Each member description has the following columns: *

      *
    1. CATALOG_NAME String (may be null) => The name of * the catalog to which this member belongs.
    2. *
    3. SCHEMA_NAME String (may be null) => The name of * the schema to which this member belongs.
    4. *
    5. CUBE_NAME String => Name of the cube to which this member * belongs.
    6. *
    7. DIMENSION_UNIQUE_NAME String => Unique name of the dimension * to which this member belongs.
    8. *
    9. HIERARCHY_UNIQUE_NAME String => Unique name of the hierarchy. * If the member belongs to more than one hierarchy, there is one * row for each hierarchy to which it belongs.
    10. *
    11. LEVEL_UNIQUE_NAME String => Unique name of the level to * which the member belongs.
    12. *
    13. LEVEL_NUMBER int => The distance of the member from the root * of the hierarchy.
    14. *
    15. MEMBER_ORDINAL int => Ordinal number of the member. Sort rank * of the member when members of this dimension are sorted in * their natural sort order. If providers do not have the concept * of natural ordering, this should be the rank when sorted by * MEMBER_NAME.
    16. *
    17. MEMBER_NAME String => Name of the member.
    18. *
    19. MEMBER_UNIQUE_NAME String => Unique name of the member.
    20. *
    21. MEMBER_TYPE int => Type of the member.
    22. *
    23. MEMBER_GUID String (may be null) => Memeber * GUID.
    24. *
    25. MEMBER_CAPTION String => A label or caption associated with * the member.
    26. *
    27. CHILDREN_CARDINALITY int => Number of children that the * member has.
    28. *
    29. PARENT_LEVEL int => The distance of the member's parent from * the root level of the hierarchy.
    30. *
    31. PARENT_UNIQUE_NAME String (may be null) => * Unique name of the member's parent.
    32. *
    33. PARENT_COUNT int => Number of parents that this member * has.
    34. *
    35. TREE_OP Enumeration (may be null) => Tree * Operation
    36. *
    37. DEPTH int (may be null) => depth
    38. *
    * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema name * as it is stored in the database; "" retrieves those without a * schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube; null means that the cube name should * not be used to narrow the search * * @param dimensionUniqueName unique name of dimension (not a pattern); * must match the * dimension name as it is stored in the database; null * means that the dimension name should not be used to narrow the * search * * @param hierarchyUniqueName unique name of hierarchy (not a pattern); * must match the * hierarchy name as it is stored in the database; null * means that the hierarchy name should not be used to narrow the * search * * @param levelUniqueName unique name of level (not a pattern); must match * the level name as it is stored in the database; null * means that the level name should not be used to narrow the * search * * @param memberUniqueName unique name of member (not a pattern); * null means that the measure unique name should not * be used to narrow the search * * @param treeOps set of tree operations to retrieve members relative * to the member whose unique name was specified; or null to return * just the member itself. * Ignored if memberUniqueName is not specified. * * @return a ResultSet object in which each row is a * member description * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.Member */ ResultSet getMembers( String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelUniqueName, String memberUniqueName, Set treeOps) throws OlapException; /** * Retrieves a result set describing the named Sets in this database. * *

    Specification as for XML/A MDSCHEMA_SETS schema rowset. * *

    Each set description has the following columns: *

      *
    1. CATALOG_NAME String (may be null) => null
    2. *
    3. SCHEMA_NAME String (may be null) => null
    4. *
    5. CUBE_NAME String => null
    6. *
    7. SET_NAME String => null
    8. *
    9. SCOPE int => null
    10. * * @param catalog a catalog name; must match the catalog name as it * is stored in the database; "" retrieves those without a catalog; * null means that the catalog name should not be used * to narrow the search * * @param schemaPattern a schema name pattern; must match the schema name * as it is stored in the database; "" retrieves those without a * schema; null means that the schema name should not * be used to narrow the search * * @param cubeNamePattern a cube name pattern; must match the * cube name as it is stored in the database; "" retrieves those * without a cube; null means that the cube name should * not be used to narrow the search * * @param setNamePattern pattern for the unique name of a set; must match * the set name as it is stored in the database; null * means that the set name should not be used to narrow the * search * * @return a ResultSet object in which each row is a * description of a named set * * @exception OlapException if a database access error occurs * * @see #getSearchStringEscape * @see org.olap4j.metadata.NamedSet */ ResultSet getSets( String catalog, String schemaPattern, String cubeNamePattern, String setNamePattern) throws OlapException; } // End OlapDatabaseMetaData.java olap4j-1.0.1.500/src/org/olap4j/Position.java0000644000175000017500000001101011707255012020310 0ustar drazzibdrazzib/* // $Id: Position.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.metadata.Member; import java.util.List; /** * Position on one of the {@link CellSetAxis} objects in a {@link CellSet}. * *

      An axis has a particular dimensionality, that is, a set of one or more * dimensions which will appear on that axis, and every position on that axis * will have a member of each of those dimensions. For example, in the MDX * query

      * *
      * SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON * COLUMNS,
      *     CrossJoin(
      *         {[Gender].Members},
      *         {[Product].[Food], * [Product].[Drink]}) ON ROWS
      * FROM [Sales]
      *
      * *

      the COLUMNS axis has dimensionality * {[Measures]} and the ROWS axis has dimensionality * {[Gender], [Product]}. In the result,

      * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
      GenderProductUnit SalesStore Sales
      All GenderFood191,940409,035.59
      All GenderDrink24,59748,836.21
      FFood94,814203,094.17
      FDrink12,20224,457.37
      MFood97,126205,941.42
      MDrink12,39524,378.84
      * *

      each of the six positions on the ROWS axis has two members, * consistent with its dimensionality of 2. The COLUMNS axis has * two positions, each with one member.

      * * @author jhyde * @version $Id: Position.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface Position { /** * Returns the list of Member objects at this position. * *

      Recall that the {@link CellSetAxisMetaData#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 Position 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 Position. */ public List getMembers(); /** * Returns the zero-based ordinal of this Position on its * {@link CellSetAxis}. * * @return ordinal of this Position */ int getOrdinal(); } // End Position.java olap4j-1.0.1.500/src/org/olap4j/mdx/0000755000175000017500000000000011540707142016441 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/mdx/WithSetNode.java0000644000175000017500000000627311707255000021505 0ustar drazzibdrazzib/* // $Id: WithSetNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.type.Type; import java.io.PrintWriter; /** * Parse tree node which declares a calculated set. Represented as the * WITH SET clause of an MDX SELECT statement. * * @version $Id: WithSetNode.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class WithSetNode implements ParseTreeNode { private final ParseRegion region; /** name of set */ private final IdentifierNode name; /** defining expression */ private ParseTreeNode expression; /** * Creates a declaration of a named set. * * @param region Region of source code * @param name Name of set * @param expression Expression to calculate set */ public WithSetNode( ParseRegion region, IdentifierNode name, ParseTreeNode expression) { this.region = region; this.name = name; this.expression = expression; } public ParseRegion getRegion() { return region; } public void unparse(ParseTreeWriter writer) { PrintWriter pw = writer.getPrintWriter(); pw.print("SET "); name.unparse(writer); writer.indent(); pw.println(" AS"); expression.unparse(writer); writer.outdent(); } /** * Returns the name of the set. * * @return name of the set */ public IdentifierNode getIdentifier() { return name; } /** * Returns the expression which calculates the set. * * @return expression which calculates the set */ public ParseTreeNode getExpression() { return expression; } /** * Sets the expression which calculates the set. * * @param expression expression which calculates the set */ public void setExpression(ParseTreeNode expression) { this.expression = expression; } public T accept(ParseTreeVisitor visitor) { final T t = visitor.visit(this); name.accept(visitor); expression.accept(visitor); return t; } public Type getType() { // not an expression throw new UnsupportedOperationException(); } public WithSetNode deepCopy() { return new WithSetNode( this.region, this.name.deepCopy(), this.expression.deepCopy()); } } // End WithSetNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/ParseRegion.java0000644000175000017500000003265111707255000021525 0ustar drazzibdrazzib/* // $Id: ParseRegion.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; /** * Region of parser source code. * *

      The main purpose of a ParseRegion is to give detailed locations in * error messages and warnings from the parsing and validation process. * *

      A region has a start and end line number and column number. A region is * a point if the start and end positions are the same. * *

      The line and column number are one-based, because that is what end-users * understand. * *

      A region's end-points are inclusive. For example, in the code * *

      SELECT FROM [Sales]
      * * the SELECT token has region [1:1, 1:6]. * *

      Regions are immutable. * * @version $Id: ParseRegion.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class ParseRegion { private final int startLine; private final int startColumn; private final int endLine; private final int endColumn; private static final String NL = System.getProperty("line.separator"); /** * Creates a ParseRegion. * *

      All lines and columns are 1-based and inclusive. For example, the * token "select" in "select from [Sales]" has a region [1:1, 1:6]. * * @param startLine Line of the beginning of the region * @param startColumn Column of the beginning of the region * @param endLine Line of the end of the region * @param endColumn Column of the end of the region */ public ParseRegion( int startLine, int startColumn, int endLine, int endColumn) { assert endLine >= startLine; assert endLine > startLine || endColumn >= startColumn; this.startLine = startLine; this.startColumn = startColumn; this.endLine = endLine; this.endColumn = endColumn; } /** * Creates a ParseRegion. * * All lines and columns are 1-based. * * @param line Line of the beginning and end of the region * @param column Column of the beginning and end of the region */ public ParseRegion( int line, int column) { this(line, column, line, column); } /** * Return starting line number (1-based). * * @return 1-based starting line number */ public int getStartLine() { return startLine; } /** * Return starting column number (1-based). * * @return 1-based starting column number */ public int getStartColumn() { return startColumn; } /** * Return ending line number (1-based). * * @return 1-based ending line number */ public int getEndLine() { return endLine; } /** * Return ending column number (1-based). * * @return 1-based starting endings column number */ public int getEndColumn() { return endColumn; } /** * Returns a string representation of this ParseRegion. * *

      Regions are of the form * [startLine:startColumn, endLine:endColumn], or * [startLine:startColumn] for point regions. * * @return string representation of this ParseRegion */ public String toString() { return "[" + startLine + ":" + startColumn + ((isPoint()) ? "" : ", " + endLine + ":" + endColumn) + "]"; } /** * Returns whether this region has the same start and end point. * * @return whether this region has the same start and end point */ public boolean isPoint() { return endLine == startLine && endColumn == startColumn; } public int hashCode() { return startLine ^ (startColumn << 2) ^ (endLine << 4) ^ (endColumn << 8); } public boolean equals(Object obj) { if (obj instanceof ParseRegion) { final ParseRegion that = (ParseRegion) obj; return this.startLine == that.startLine && this.startColumn == that.startColumn && this.endLine == that.endLine && this.endColumn == that.endColumn; } else { return false; } } /** * Combines this region with a list of parse tree nodes to create a * region which spans from the first point in the first to the last point * in the other. * * @param regions Collection of source code regions * @return region which represents the span of the given regions */ public ParseRegion plusAll(Iterable regions) { return sum( regions, getStartLine(), getStartColumn(), getEndLine(), getEndColumn()); } /** * Combines the parser positions of a list of nodes to create a position * which spans from the beginning of the first to the end of the last. * * @param nodes Collection of parse tree nodes * @return region which represents the span of the given nodes */ public static ParseRegion sum( Iterable nodes) { return sum(nodes, Integer.MAX_VALUE, Integer.MAX_VALUE, -1, -1); } private static ParseRegion sum( Iterable regions, int startLine, int startColumn, int endLine, int endColumn) { int testLine; int testColumn; for (ParseRegion region : regions) { if (region == null) { continue; } testLine = region.getStartLine(); testColumn = region.getStartColumn(); if ((testLine < startLine) || ((testLine == startLine) && (testColumn < startColumn))) { startLine = testLine; startColumn = testColumn; } testLine = region.getEndLine(); testColumn = region.getEndColumn(); if ((testLine > endLine) || ((testLine == endLine) && (testColumn > endColumn))) { endLine = testLine; endColumn = testColumn; } } return new ParseRegion(startLine, startColumn, endLine, endColumn); } /** * Looks for one or two carets in an MDX string, and if present, converts * them into a parser position. * *

      Examples: * *

        *
      • findPos("xxx^yyy") yields {"xxxyyy", position 3, line 1 column 4} *
      • findPos("xxxyyy") yields {"xxxyyy", null} *
      • findPos("xxx^yy^y") yields {"xxxyyy", position 3, line 4 column 4 * through line 1 column 6} *
      * * @param code Source code * @return object containing source code annotated with region */ public static RegionAndSource findPos(String code) { int firstCaret = code.indexOf('^'); if (firstCaret < 0) { return new RegionAndSource(code, null); } int secondCaret = code.indexOf('^', firstCaret + 1); if (secondCaret < 0) { String codeSansCaret = code.substring(0, firstCaret) + code.substring(firstCaret + 1); int [] start = indexToLineCol(code, firstCaret); return new RegionAndSource( codeSansCaret, new ParseRegion(start[0], start[1])); } else { String codeSansCaret = code.substring(0, firstCaret) + code.substring(firstCaret + 1, secondCaret) + code.substring(secondCaret + 1); int [] start = indexToLineCol(code, firstCaret); // subtract 1 because first caret pushed the string out --secondCaret; // subtract 1 because the col position needs to be inclusive --secondCaret; int [] end = indexToLineCol(code, secondCaret); return new RegionAndSource( codeSansCaret, new ParseRegion(start[0], start[1], end[0], end[1])); } } /** * Returns the (1-based) line and column corresponding to a particular * (0-based) offset in a string. * *

      Converse of {@link #lineColToIndex(String, int, int)}. * * @param code Source code * @param i Offset within source code * @return 2-element array containing line and column */ private static int [] indexToLineCol(String code, int i) { int line = 0; int j = 0; while (true) { String s; int rn = code.indexOf("\r\n", j); int r = code.indexOf("\r", j); int n = code.indexOf("\n", j); int prevj = j; if ((r < 0) && (n < 0)) { assert rn < 0; s = null; j = -1; } else if ((rn >= 0) && (rn < n) && (rn <= r)) { s = "\r\n"; j = rn; } else if ((r >= 0) && (r < n)) { s = "\r"; j = r; } else { s = "\n"; j = n; } if ((j < 0) || (j > i)) { return new int[] { line + 1, i - prevj + 1 }; } assert s != null; j += s.length(); ++line; } } /** * Finds the position (0-based) in a string which corresponds to a given * line and column (1-based). * *

      Converse of {@link #indexToLineCol(String, int)}. * * @param code Source code * @param line Line number * @param column Column number * @return Offset within source code */ private static int lineColToIndex(String code, int line, int column) { --line; --column; int i = 0; while (line-- > 0) { // Works on linux where line ending is "\n"; // also works on windows where line ending is "\r\n". // Even works if they supply linux strings on windows. i = code.indexOf("\n", i) + "\n".length(); } return i + column; } /** * Generates a string of the source code annotated with caret symbols ("^") * at the beginning and end of the region. * *

      For example, for the region (1, 9, 1, 12) and source * "values (foo)", * yields the string "values (^foo^)". * * @param source Source code * @return Source code annotated with position */ public String annotate(String source) { return addCarets(source, startLine, startColumn, endLine, endColumn); } /** * Converts a string to a string with one or two carets in it. For example, * addCarets("values (foo)", 1, 9, 1, 11) yields "values * (^foo^)". * * @param sql Source code * @param line Line number * @param col Column number * @param endLine Line number of end of region * @param endCol Column number of end of region * @return String annotated with region */ private static String addCarets( String sql, int line, int col, int endLine, int endCol) { String sqlWithCarets; int cut = lineColToIndex(sql, line, col); sqlWithCarets = sql.substring(0, cut) + "^" + sql.substring(cut); if ((col != endCol) || (line != endLine)) { cut = lineColToIndex(sqlWithCarets, endLine, endCol + 1); ++cut; // for caret if (cut < sqlWithCarets.length()) { sqlWithCarets = sqlWithCarets.substring(0, cut) + "^" + sqlWithCarets.substring(cut); } else { sqlWithCarets += "^"; } } return sqlWithCarets; } /** * Combination of a region within an MDX statement with the source text * of the whole MDX statement. * *

      Useful for reporting errors. For example, the error in the statement * *

      *
           * SELECT {[Measures].[Units In Stock]} ON COLUMNS
           * FROM [Sales]
           * 
      *
      * * has source * "SELECT {[Measures].[Units In Stock]} ON COLUMNS\nFROM [Sales]" and * region [1:9, 1:34]. */ public static class RegionAndSource { public final String source; public final ParseRegion region; /** * Creates a RegionAndSource. * * @param source Source MDX code * @param region Coordinates of region within MDX code */ public RegionAndSource(String source, ParseRegion region) { this.source = source; this.region = region; } } } // End ParseRegion.java olap4j-1.0.1.500/src/org/olap4j/mdx/MdxUtil.java0000644000175000017500000000623011707255000020667 0ustar drazzibdrazzib/* // $Id: MdxUtil.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import java.io.StringWriter; import java.util.*; import java.util.regex.Pattern; /** * Utility methods for MDX parsing. * *

      NOTE: Package protected. Not part of the public olap4j API. * * @author jhyde * @version $Id: MdxUtil.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 6, 2007 */ class MdxUtil { private static final Pattern QUOT_PATTERN = Pattern.compile("\"", Pattern.LITERAL); /** * Converts a string into a double-quoted string. * * @param val String * @return String enclosed in double-quotes */ static String quoteForMdx(String val) { StringBuilder buf = new StringBuilder(val.length() + 20); buf.append("\""); buf.append(QUOT_PATTERN.matcher(val).replaceAll("\"\"")); buf.append("\""); return buf.toString(); } static String toString(ParseTreeNode node) { StringWriter sw = new StringWriter(); ParseTreeWriter parseTreeWriter = new ParseTreeWriter(sw); node.unparse(parseTreeWriter); return sw.toString(); } /** * Encodes string for MDX (escapes ] as ]] inside a name). * * @param st String * @return String escaped for inclusion in an MDX identifier */ static String mdxEncodeString(String st) { StringBuilder retString = new StringBuilder(st.length() + 20); for (int i = 0; i < st.length(); i++) { char c = st.charAt(i); if ((c == ']') && ((i + 1) < st.length()) && (st.charAt(i + 1) != '.')) { retString.append(']'); // escaping character } retString.append(c); } return retString.toString(); } /** * Creates a deep copy of a list. * * @param list List to be copied * @return Copy of list, with each element deep copied */ @SuppressWarnings({"unchecked"}) static List deepCopyList(List list) { // Don't make a copy of the system empty list. '==' is intentional. if (list == Collections.EMPTY_LIST) { return list; } final ArrayList listCopy = new ArrayList(list.size()); for (E e : list) { listCopy.add((E) e.deepCopy()); } return listCopy; } } // End MdxUtil.java olap4j-1.0.1.500/src/org/olap4j/mdx/AxisNode.java0000644000175000017500000001246711707255000021024 0ustar drazzibdrazzib/* // $Id: AxisNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.Axis; import org.olap4j.type.Type; import java.io.PrintWriter; import java.util.Collections; import java.util.List; /** * An axis in an MDX query. For example, the typical MDX query has two axes, * which appear as the "ON COLUMNS" and "ON ROWS" clauses. * * @version $Id: AxisNode.java 482 2012-01-05 23:27:27Z jhyde $ */ public class AxisNode implements ParseTreeNode { private final ParseRegion region; private boolean nonEmpty; private ParseTreeNode expression; private final Axis axis; private final List dimensionProperties; /** * Creates an axis. * * @param region Region of source code * @param nonEmpty Whether to filter out members of this axis whose cells * are all empty * @param axis Which axis (ROWS, COLUMNS, etc.) * @param dimensionProperties List of dimension properties; if null, * empty list is assumed * @param expression Expression to populate the axis */ public AxisNode( ParseRegion region, boolean nonEmpty, Axis axis, List dimensionProperties, ParseTreeNode expression) { this.region = region; this.nonEmpty = nonEmpty; this.expression = expression; this.axis = axis; if (axis == null) { throw new IllegalArgumentException("Axis type must not be null"); } if (dimensionProperties == null) { dimensionProperties = Collections.emptyList(); } this.dimensionProperties = dimensionProperties; } public ParseRegion getRegion() { return region; } public T accept(ParseTreeVisitor visitor) { final T o = visitor.visit(this); // visit the expression which forms the axis expression.accept(visitor); return o; } /** * Returns the name of the axis this axis expression is populating. * * @return axis name */ public Axis getAxis() { return axis; } /** * Returns whether the axis has the NON EMPTY property set. * * @return whether the axis is NON EMPTY */ public boolean isNonEmpty() { return nonEmpty; } /** * Sets whether the axis has the NON EMPTY property set. * * See {@link #isNonEmpty()}. * * @param nonEmpty whether the axis is NON EMPTY */ public void setNonEmpty(boolean nonEmpty) { this.nonEmpty = nonEmpty; } /** * Returns the expression which is used to compute the value of this axis. * * @return the expression which is used to compute the value of this axis */ public ParseTreeNode getExpression() { return expression; } /** * Sets the expression which is used to compute the value of this axis. * See {@link #getExpression()}. * * @param expr the expression which is used to compute the value of this * axis */ public void setExpression(ParseTreeNode expr) { this.expression = expr; } public void unparse(ParseTreeWriter writer) { PrintWriter pw = writer.getPrintWriter(); if (nonEmpty) { pw.print("NON EMPTY "); } if (expression != null) { expression.unparse(writer); } if (dimensionProperties.size() > 0) { pw.print(" DIMENSION PROPERTIES "); for (int i = 0; i < dimensionProperties.size(); i++) { IdentifierNode dimensionProperty = dimensionProperties.get(i); if (i > 0) { pw.print(", "); } dimensionProperty.unparse(writer); } } if (axis != Axis.FILTER) { pw.print(" ON " + axis); } } /** * Returns the list of dimension properties of this axis. * * @return list of dimension properties */ public List getDimensionProperties() { return dimensionProperties; } public Type getType() { // An axis is not an expression, so does not have a type. // Try AxisNode.getExpression().getType() instead. return null; } public AxisNode deepCopy() { return new AxisNode( this.region, this.nonEmpty, this.axis, MdxUtil.deepCopyList(dimensionProperties), this.expression != null ? this.expression.deepCopy() : null); } } // End AxisNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/DimensionNode.java0000644000175000017500000000456411707255000022044 0ustar drazzibdrazzib/* // $Id: DimensionNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.metadata.Dimension; import org.olap4j.type.DimensionType; import org.olap4j.type.Type; /** * Usage of a {@link org.olap4j.metadata.Dimension} as an expression in an MDX * parse tree. * * @author jhyde * @version $Id: DimensionNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public class DimensionNode implements ParseTreeNode { private final ParseRegion region; private final Dimension dimension; /** * Creates a DimensionNode. * * @param region Region of source code * @param dimension Dimension which is used in the expression */ public DimensionNode( ParseRegion region, Dimension dimension) { this.region = region; this.dimension = dimension; } public ParseRegion getRegion() { return region; } /** * Returns the Dimension used in this expression. * * @return dimension used in this expression */ public Dimension getDimension() { return dimension; } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public Type getType() { return new DimensionType(dimension); } public void unparse(ParseTreeWriter writer) { writer.getPrintWriter().print(dimension.getUniqueName()); } public String toString() { return dimension.getUniqueName(); } public DimensionNode deepCopy() { // DimensionNode is immutable return this; } } // End DimensionNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/LiteralNode.java0000644000175000017500000001271411707255000021507 0ustar drazzibdrazzib/* // $Id: LiteralNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.impl.Olap4jUtil; import org.olap4j.type.*; import java.io.PrintWriter; import java.math.BigDecimal; /** * Represents a constant value, such as a string or number, in a parse tree. * *

      Symbols, such as the ASC keyword in * Order([Store].Members, [Measures].[Unit Sales], ASC), are * also represented as Literals. * *

      A LiteralNode is immutable. * * @version $Id: LiteralNode.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class LiteralNode implements ParseTreeNode { // Data members. private final Object value; private final Type type; private final ParseRegion region; /** * Private constructor. * *

      Use the creation methods {@link #createString} etc. * * @param region Region of source code * @param type Type of this literal; must not be null * @param value Value of this literal, must be null only if this is the * null literal */ private LiteralNode( ParseRegion region, Type type, Object value) { assert type != null; assert (type instanceof NullType) == (value == null); assert (type instanceof StringType || type instanceof SymbolType) == (value instanceof String); assert (type instanceof NumericType) == (value instanceof BigDecimal); this.region = region; this.type = type; this.value = value; } /** * Creates a literal with the NULL value. * * @param region Region of source code * @return literal representing the NULL value */ public static LiteralNode createNull(ParseRegion region) { return new LiteralNode(region, new NullType(), null); } /** * Creates a string literal. * * @param region Region of source code * @param value String value * * @return literal representing the string value * * @see #createSymbol */ public static LiteralNode createString( ParseRegion region, String value) { if (value == null) { throw new IllegalArgumentException("value must not be null"); } return new LiteralNode(region, new StringType(), value); } /** * Creates a symbol literal. * * @param region Region of source code * @param value Name of symbol * * @return literal representing the symbol value * * @see #createString */ public static LiteralNode createSymbol( ParseRegion region, String value) { if (value == null) { throw new IllegalArgumentException("value must not be null"); } return new LiteralNode(region, new SymbolType(), value); } /** * Creates a numeric literal. * * @param region Region of source code * @param value Value of literal; must not be null * @param approximate Whether the literal is approximate * * @return literal representing the integer value */ public static LiteralNode createNumeric( ParseRegion region, BigDecimal value, boolean approximate) { if (value == null) { throw new IllegalArgumentException("value must not be null"); } Olap4jUtil.discard(approximate); // reserved for future use return new LiteralNode(region, new NumericType(), value); } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public Type getType() { return type; } public ParseRegion getRegion() { return region; } /** * Returns the value of this literal. * *

      Value is always of type {@link String} (if the literal is a string or * a symbol), of type {@link java.math.BigDecimal} (if the literal is * numeric), or null (if the literal is of null type). * * @return value */ public Object getValue() { return value; } public void unparse(ParseTreeWriter writer) { PrintWriter pw = writer.getPrintWriter(); if (value == null) { pw.print("NULL"); } else if (type instanceof SymbolType) { pw.print(value); } else if (type instanceof NumericType) { pw.print(value); } else if (type instanceof StringType) { pw.print(MdxUtil.quoteForMdx((String) value)); } else { throw new AssertionError("unexpected literal type " + type); } } public LiteralNode deepCopy() { // No need to copy: literal nodes are immutable. return this; } } // End LiteralNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/package.html0000644000175000017500000000020611421322450020711 0ustar drazzibdrazzib Provides an object model to represent statements and expressions in the MDX lanaugage as a parse tree. olap4j-1.0.1.500/src/org/olap4j/mdx/ParseTreeWriter.java0000644000175000017500000000620311707255000022370 0ustar drazzibdrazzib/* // $Id: ParseTreeWriter.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import java.io.PrintWriter; import java.io.Writer; /** * Writer for MDX parse tree. * *

      Typical use is with the {@link ParseTreeNode#unparse(ParseTreeWriter)} * method as follows: * *

      *
       * ParseTreeNode node;
       * StringWriter sw = new StringWriter();
       * PrintWriter pw = new PrintWriter(sw);
       * ParseTreeWriter mdxWriter = new ParseTreeWriter(pw);
       * node.unparse(mdxWriter);
       * pw.flush();
       * String mdx = sw.toString();
       * 
      *
      * * * @see org.olap4j.mdx.ParseTreeNode#unparse(ParseTreeWriter) * * @author jhyde * @version $Id: ParseTreeWriter.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public class ParseTreeWriter { private final PrintWriter pw; private int linePrefixLength; private String linePrefix; private static final int INDENT = 4; private static String bigString = " "; /** * Creates a ParseTreeWriter. * * @param pw Underlying writer */ public ParseTreeWriter(PrintWriter pw) { this((Writer)pw); } /** * Creates a ParseTreeWriter. * * @param w Underlying writer */ public ParseTreeWriter(Writer w) { this.pw = new PrintWriter(w) { @Override public void println() { super.println(); print(linePrefix); } }; this.linePrefixLength = 0; setPrefix(); } /** * Returns the print writer. * * @return print writer */ public PrintWriter getPrintWriter() { return pw; } /** * Increases the indentation level. */ public void indent() { linePrefixLength += INDENT; setPrefix(); } private void setPrefix() { linePrefix = spaces(linePrefixLength); } /** * Decreases the indentation level. */ public void outdent() { linePrefixLength -= INDENT; setPrefix(); } /** * Returns a string of N spaces. * @param n Number of spaces * @return String of N spaces */ private static synchronized String spaces(int n) { while (n > bigString.length()) { bigString = bigString + bigString; } return bigString.substring(0, n); } } // End ParseTreeWriter.java olap4j-1.0.1.500/src/org/olap4j/mdx/WithMemberNode.java0000644000175000017500000001060311707255000022151 0ustar drazzibdrazzib/* // $Id: WithMemberNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.type.Type; import java.io.PrintWriter; import java.util.List; /** * Parse tree node which declares a calculated member. Represented as the * WITH MEMBER clause of an MDX SELECT statement. * * @version $Id: WithMemberNode.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class WithMemberNode implements ParseTreeNode { private final ParseRegion region; /** name of set or member */ private final IdentifierNode name; /** defining expression */ private ParseTreeNode expression; // properties of member, such as SOLVE_ORDER private final List memberPropertyList; /** * Constructs a formula specifying a member. * * @param region Source code region * @param name Name of member being declared * @param exp Expression for value of member * @param memberPropertyList Collection of properties of member */ public WithMemberNode( ParseRegion region, IdentifierNode name, ParseTreeNode exp, List memberPropertyList) { this.region = region; this.name = name; this.expression = exp; this.memberPropertyList = memberPropertyList; } public ParseRegion getRegion() { return region; } public void unparse(ParseTreeWriter writer) { PrintWriter pw = writer.getPrintWriter(); pw.print("MEMBER "); name.unparse(writer); writer.indent(); pw.println(" AS"); // The MDX language, and olap4j's parser, allows formulas in calculated // members and sets to be specified with and without single quotes. expression.unparse(writer); if (memberPropertyList != null) { for (PropertyValueNode memberProperty : memberPropertyList) { pw.print(", "); memberProperty.unparse(writer); } } writer.outdent(); } /** * Returns the name of the member declared. * *

      The name is as specified in the parse tree; it may not be identical * to the unique name of the member. * * @return Name of member */ public IdentifierNode getIdentifier() { return name; } /** * Returns the expression to evaluate to calculate the member. * * @return expression */ public ParseTreeNode getExpression() { return expression; } /** * Sets the expression to evaluate to calculate the member. * * @param expression Expression */ public void setExpression(ParseTreeNode expression) { this.expression = expression; } public T accept(ParseTreeVisitor visitor) { T t = visitor.visit(this); name.accept(visitor); expression.accept(visitor); return t; } public Type getType() { // not an expression throw new UnsupportedOperationException(); } /** * Returns the list of properties of this member. * *

      The list may be empty, but is never null. * Each entry is a (name, expression) pair. * * @return list of properties */ public List getMemberPropertyList() { return memberPropertyList; } public WithMemberNode deepCopy() { return new WithMemberNode( this.region, // immutable this.name.deepCopy(), this.expression.deepCopy(), MdxUtil.deepCopyList(memberPropertyList)); } } // End WithMemberNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/ParameterNode.java0000644000175000017500000001067511707255000022037 0ustar drazzibdrazzib/* // $Id: ParameterNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.type.Type; import java.io.PrintWriter; /** * A parameter to an MDX query. * *

      Not all dialects of MDX support parameters. If a dialect supports * parameters, the driver for that dialect should extend the parser to * introduce a ParameterNode into the parse tree wherever a parameter is * encountered. * *

      For example, in Mondrian's dialect of MDX, a call to the Param(name, * type, defaultValueExpr) function introduces a parameter, and * ParamRef(name) creates a reference to a parameter defined * elsewhere in the query. * * @version $Id: ParameterNode.java 482 2012-01-05 23:27:27Z jhyde $ */ public class ParameterNode implements ParseTreeNode { private String name; private Type type; private ParseTreeNode defaultValueExpression; private final ParseRegion region; /** * Creates a ParameterNode. * *

      The name must not be null, and the * defaultValueExpression must be consistent with the * type. * * @param region Region of source code * @param name Name of parameter * @param type Type of parameter * @param defaultValueExpression Expression which yields the default value * of the parameter */ public ParameterNode( ParseRegion region, String name, Type type, ParseTreeNode defaultValueExpression) { assert name != null; assert type != null; assert defaultValueExpression != null; this.region = region; this.name = name; this.type = type; this.defaultValueExpression = defaultValueExpression; } public ParseRegion getRegion() { return region; } public T accept(ParseTreeVisitor visitor) { final T t = visitor.visit(this); defaultValueExpression.accept(visitor); return t; } public void unparse(ParseTreeWriter writer) { PrintWriter pw = writer.getPrintWriter(); pw.print("Param("); pw.print(MdxUtil.quoteForMdx(name)); pw.print(", "); pw.print(type); pw.print(", "); defaultValueExpression.unparse(writer); pw.print(")"); } public Type getType() { // not an expression return null; } /** * Returns the name of this parameter. * * @return name of this parameter */ public String getName() { return name; } /** * Sets the name of this parameter. * * @param name Parameter name */ public void setName(String name) { this.name = name; } /** * Sets the type of this parameter. * * @param type Type */ public void setType(Type type) { this.type = type; } /** * Returns the expression which yields the default value of this parameter. * * @return expression which yields the default value of this parameter */ public ParseTreeNode getDefaultValueExpression() { return defaultValueExpression; } /** * Sets the expression which yields the default value of this parameter. * * @param defaultValueExpression default value expression */ public void setDefaultValueExpression(ParseTreeNode defaultValueExpression) { this.defaultValueExpression = defaultValueExpression; } public ParameterNode deepCopy() { return new ParameterNode( this.region, this.name, this.type, // types are immutable this.defaultValueExpression.deepCopy()); } } // End ParameterNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/ParseTreeNode.java0000644000175000017500000000572011707255000022004 0ustar drazzibdrazzib/* // $Id: ParseTreeNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.type.Type; /** * Node in a parse tree representing a parsed MDX statement. * *

      To convert a parse tree to an MDX string, use a {@link ParseTreeWriter} * and the {@link #unparse(ParseTreeWriter)} method. * * @author jhyde * @version $Id: ParseTreeNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public interface ParseTreeNode { /** * Accepts a visitor to this MDX parse tree node. * *

      The implementation should generally dispatches to the * {@link ParseTreeVisitor#visit} method appropriate to the type of expression. * * @param visitor Visitor * @return T, the specific return type of the visitor */ T accept(ParseTreeVisitor visitor); /** * Returns the type of this expression. * *

      Returns null if this node is not an expression, for instance a * SELECT node. * * @return type of this expression */ Type getType(); /** * Converts this node into MDX text. * * @param writer Parse tree writer */ void unparse(ParseTreeWriter writer); /** * Returns the region of the source code which this node was created from, * if it was created by parsing. * *

      A non-leaf node's region will encompass the regions of all of its * children. For example, a the region of a function call node * Crossjoin([Gender], {[Store].[USA]}) stretches from * the first character of the function name to the closing parenthesis. * *

      Region may be null, if the node was created programmatically, not * from a piece of source code. * * @return Region of the source code this node was created from, if it was * created by parsing */ ParseRegion getRegion(); /** * Creates a deep copy of this ParseTreeNode object. * *

      Note: implementing classes can return the concrete type instead * of ParseTreeNode (using Java 1.5 covariant return types) * * @return The deep copy of this ParseTreeNode */ ParseTreeNode deepCopy(); } // End ParseTreeNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/CallNode.java0000644000175000017500000001617611707255000020774 0ustar drazzibdrazzib/* // $Id: CallNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.type.Type; import java.util.Arrays; import java.util.List; /** * A parse tree node representing a call to a function or operator. * *

      Examples of calls include:

        *
      • 5 + 2, a call to the infix arithmetic operator '+'
      • *
      • [Measures].[Unit Sales] IS NULL, a call applying the * {@link Syntax#Postfix postfix} operator * IS NULL to a member expression
      • *
      • CrossJoin({[Gender].Children}, {[Store]}), a call to the * CrossJoin function
      • *
      • [Gender].Children, a call to the Children * operator, which has {@link Syntax#Property property syntax}
      • *
      • [Gender].Properties("FORMAT_STRING"), a call to the * Properties operator, which has * {@link Syntax#Method method syntax}
      • *
      * * @author jhyde * @version $Id: CallNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jan 6, 2006 */ public class CallNode implements ParseTreeNode { private final String name; private final Syntax syntax; private final List argList; private final ParseRegion region; private Type type; /** * Creates a CallNode. * *

      The syntax argument determines whether this is a prefix, * infix or postfix operator, a function call, and so forth. * *

      The list of arguments args must be specified, even if * there are zero arguments, and each argument must be not null. * *

      The type is initially null, but can be set using {@link #setType} * after validation. * * @param region Region of source code * @param name Name of operator or function * @param syntax Syntax of call * @param args List of zero or more arguments */ public CallNode( ParseRegion region, String name, Syntax syntax, List args) { this.region = region; assert name != null; assert syntax != null; assert args != null; this.name = name; this.syntax = syntax; this.argList = args; // Check special syntaxes. switch (syntax) { case Braces: assert name.equals("{}"); break; case Parentheses: assert name.equals("()"); break; case Internal: assert name.startsWith("$"); break; case Empty: assert name.equals(""); break; default: assert !name.startsWith("$") && !name.equals("{}") && !name.equals("()"); break; } } /** * Creates an CallNode using a variable number of arguments. * *

      The syntax argument determines whether this is a prefix, * infix or postfix operator, a function call, and so forth. * *

      The list of arguments args must be specified, even if * there are zero arguments, and each argument must be not null. * * @param region Region of source code * @param name Name of operator or function * @param syntax Syntax of call * @param args List of zero or more arguments */ public CallNode( ParseRegion region, String name, Syntax syntax, ParseTreeNode... args) { this(region, name, syntax, Arrays.asList(args)); } public ParseRegion getRegion() { return region; } /** * Sets the type of this CallNode. * *

      Typically, this method would be called by the validator when it has * deduced the argument types, chosen between any overloaded functions * or operators, and determined the result type of the function or * operator. * * @param type Result type of this call */ public void setType(Type type) { this.type = type; } public Type getType() { return type; } public void unparse(ParseTreeWriter writer) { syntax.unparse(name, argList, writer); } public T accept(ParseTreeVisitor visitor) { final T o = visitor.visit(this); // visit the call's arguments for (ParseTreeNode arg : argList) { arg.accept(visitor); } return o; } /** * Returns the name of the function or operator. * * @return name of the function or operator */ public String getOperatorName() { return name; } /** * Returns the syntax of this call. * * @return the syntax of the call */ public Syntax getSyntax() { return syntax; } /** * Returns the list of arguments to this call. * * @return list of arguments */ public List getArgList() { return argList; } public CallNode deepCopy() { return new CallNode( this.region, this.name, this.syntax, MdxUtil.deepCopyList(argList)); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((argList == null) ? 0 : argList.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((syntax == null) ? 0 : syntax.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } CallNode other = (CallNode) obj; if (argList == null) { if (other.argList != null) { return false; } } else if (!argList.equals(other.argList)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (syntax == null) { if (other.syntax != null) { return false; } } else if (!syntax.equals(other.syntax)) { return false; } return true; } } // End CallNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/MemberNode.java0000644000175000017500000000462211707255000021321 0ustar drazzibdrazzib/* // $Id: MemberNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.metadata.Member; import org.olap4j.type.MemberType; import org.olap4j.type.Type; /** * Usage of a {@link org.olap4j.metadata.Member} as an expression in an MDX * parse tree. * * @author jhyde * @version $Id: MemberNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public class MemberNode implements ParseTreeNode { private final ParseRegion region; private final Member member; /** * Creates a MemberNode. * * @param region Region of source code * @param member Member which is used in the expression */ public MemberNode( ParseRegion region, Member member) { this.region = region; this.member = member; } public ParseRegion getRegion() { return region; } /** * Returns the Member used in this expression. * * @return member used in this expression */ public Member getMember() { return member; } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public Type getType() { return new MemberType( member.getDimension(), member.getHierarchy(), member.getLevel(), member); } public void unparse(ParseTreeWriter writer) { writer.getPrintWriter().print(member.getUniqueName()); } public String toString() { return member.getUniqueName(); } public MemberNode deepCopy() { // MemberNode is immutable return this; } } // End MemberNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/HierarchyNode.java0000644000175000017500000000464711707255000022037 0ustar drazzibdrazzib/* // $Id: HierarchyNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.metadata.Hierarchy; import org.olap4j.type.HierarchyType; import org.olap4j.type.Type; /** * Usage of a {@link org.olap4j.metadata.Hierarchy} as an expression in an MDX * parse tree. * * @author jhyde * @version $Id: HierarchyNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public class HierarchyNode implements ParseTreeNode { private final ParseRegion region; private final Hierarchy hierarchy; /** * Creates a HierarchyNode. * * @param region Region of source code * @param hierarchy Hierarchy which is used in the expression */ public HierarchyNode( ParseRegion region, Hierarchy hierarchy) { this.region = region; this.hierarchy = hierarchy; } public ParseRegion getRegion() { return region; } /** * Returns the Hierarchy used in this expression. * * @return hierarchy used in this expression */ public Hierarchy getHierarchy() { return hierarchy; } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public Type getType() { return new HierarchyType( hierarchy.getDimension(), hierarchy); } public void unparse(ParseTreeWriter writer) { writer.getPrintWriter().print(hierarchy.getUniqueName()); } public String toString() { return hierarchy.getUniqueName(); } public HierarchyNode deepCopy() { // HierarchyNode is immutable return this; } } // End HierarchyNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/Syntax.java0000644000175000017500000002547611707255000020604 0ustar drazzibdrazzib/* // $Id: Syntax.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import java.io.PrintWriter; import java.util.List; /** * Enumerated values describing the syntax of an expression. * * @author jhyde * @since 21 July, 2003 * @version $Id: Syntax.java 482 2012-01-05 23:27:27Z jhyde $ */ public enum Syntax { /** * Defines syntax for expression invoked FUNCTION() or * FUNCTION(args). */ Function { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { unparseList(writer, argList, operatorName + "(", ", ", ")"); } }, /** * Defines syntax for expression invoked as object.PROPERTY. */ Property { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { assert argList.size() == 1; argList.get(0).unparse(writer); // 'this' writer.getPrintWriter().print("."); writer.getPrintWriter().print(operatorName); } }, /** * Defines syntax for expression invoked invoked as * object.METHOD() or * object.METHOD(args). */ Method { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { assert argList.size() >= 1; argList.get(0).unparse(writer); // 'this' final PrintWriter pw = writer.getPrintWriter(); pw.print("."); pw.print(operatorName); pw.print("("); for (int i = 1; i < argList.size(); i++) { if (i > 1) { pw.print(", "); } argList.get(i).unparse(writer); } pw.print(")"); } }, /** * Defines syntax for expression invoked as arg OPERATOR arg * (like '+' or 'AND'). */ Infix { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { if (needParen(argList)) { unparseList( writer, argList, "(", " " + operatorName + " ", ")"); } else { unparseList( writer, argList, "", " " + operatorName + " ", ""); } } }, /** * Defines syntax for expression invoked as OPERATOR arg * (like unary '-'). */ Prefix { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { if (needParen(argList)) { unparseList( writer, argList, "(" + operatorName + " ", null, ")"); } else { unparseList( writer, argList, operatorName + " ", null, ""); } } }, /** * Defines syntax for expression invoked as arg OPERATOR * (like IS EMPTY). */ Postfix { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { if (needParen(argList)) { unparseList( writer, argList, "(", null, " " + operatorName + ")"); } else { unparseList( writer, argList, "", null, " " + operatorName); } } }, /** * Defines syntax for expression invoked as * {ARG, ...}; that * is, the set construction operator. */ Braces { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { unparseList( writer, argList, "{", ", ", "}"); } }, /** * Defines syntax for expression invoked as (ARG) or * (ARG, ...); that is, parentheses for grouping * expressions, and the tuple construction operator. */ Parentheses { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { if (argList.size() == 1 && argList.get(0) instanceof CallNode && needParen(((CallNode) argList.get(0)).getArgList())) { // The parenthesized expression is going to defensively // parenthesize itself. So, don't add another layer. argList.get(0).unparse(writer); } else { unparseList( writer, argList, "(", ", ", ")"); } } }, /** * Defines syntax for expression invoked as CASE ... END. */ Case { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { final PrintWriter pw = writer.getPrintWriter(); if (operatorName.equals("_CaseTest")) { pw.print("CASE"); int j = 0; int clauseCount = (argList.size() - j) / 2; for (int i = 0; i < clauseCount; i++) { pw.print(" WHEN "); argList.get(j++).unparse(writer); pw.print(" THEN "); argList.get(j++).unparse(writer); } if (j < argList.size()) { pw.print(" ELSE "); argList.get(j++).unparse(writer); } assert j == argList.size(); pw.print(" END"); } else { assert operatorName.equals("_CaseMatch"); pw.print("CASE "); int j = 0; argList.get(j++).unparse(writer); int clauseCount = (argList.size() - j) / 2; for (int i = 0; i < clauseCount; i++) { pw.print(" WHEN "); argList.get(j++).unparse(writer); pw.print(" THEN "); argList.get(j++).unparse(writer); } if (j < argList.size()) { pw.print(" ELSE "); argList.get(j++).unparse(writer); } assert j == argList.size(); pw.print(" END"); } } }, /** * Defines syntax for expression generated by the system which * cannot be specified syntactically. */ Internal, /** * Defines syntax for a CAST expression * CAST(expression AS type). */ Cast { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { writer.getPrintWriter().print("CAST("); argList.get(0).unparse(writer); writer.getPrintWriter().print(" AS "); argList.get(1).unparse(writer); writer.getPrintWriter().print(")"); } }, /** * Defines syntax for expression invoked object.&PROPERTY * (a variant of {@link #Property}). */ QuotedProperty, /** * Defines syntax for expression invoked object.[&PROPERTY] * (a variant of {@link #Property}). */ AmpersandQuotedProperty, /** * Defines the syntax for an empty expression. Empty expressions can occur * within function calls, and are denoted by a pair of commas with only * whitespace between them, for example * *

      * DrillDownLevelTop({[Product].[All Products]}, 3, , * [Measures].[Unit Sales]) *
      */ Empty { public void unparse( String operatorName, List argList, ParseTreeWriter writer) { assert argList.size() == 0; } }; /** * Converts a call to a function of this syntax into source code. * * @param operatorName Operator name * @param argList List of arguments * @param writer Writer */ public void unparse( String operatorName, List argList, ParseTreeWriter writer) { throw new UnsupportedOperationException(); } /** * Returns whether a collection of parse tree nodes need to be enclosed * in parentheses. * * @param args Parse tree nodes * @return Whether nodes need to be enclosed in parentheses */ private static boolean needParen(List args) { return !(args.size() == 1 && args.get(0) instanceof CallNode && ((CallNode) args.get(0)).getSyntax() == Parentheses); } private static void unparseList( ParseTreeWriter writer, List argList, String start, String mid, String end) { final PrintWriter pw = writer.getPrintWriter(); pw.print(start); for (int i = 0; i < argList.size(); i++) { if (i > 0) { pw.print(mid); } argList.get(i).unparse(writer); } pw.print(end); } } // End Syntax.java olap4j-1.0.1.500/src/org/olap4j/mdx/IdentifierNode.java0000644000175000017500000002300411707255000022167 0ustar drazzibdrazzib/* // $Id: IdentifierNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.impl.*; import org.olap4j.type.Type; import java.util.*; /** * Multi-part identifier. * *

      An identifier is immutable. * *

      An identifer consists of one or more {@link IdentifierSegment}s. A segment * is either:

        *
      • An unquoted value such as '{@code CA}', *
      • A value quoted in brackets, such as '{@code [San Francisco]}', or *
      • A key of one or more parts, each of which is prefixed with '&', * such as '{@code &[Key 1]&Key2&[5]}'. *
      * *

      Segment types are indicated by the {@link Quoting} enumeration. * *

      A key segment is of type {@link Quoting#KEY}, and has one or more * component parts accessed via the * {@link IdentifierSegment#getKeyParts()} method. The parts * are of type {@link Quoting#UNQUOTED} or {@link Quoting#QUOTED}. * *

      A simple example is the identifier {@code Measures.[Unit Sales]}. It * has two segments:

        *
      • Segment #0 is * {@link Quoting#UNQUOTED UNQUOTED}, * name "Measures"
      • *
      • Segment #1 is * {@link Quoting#QUOTED QUOTED}, * name "Unit Sales"
      • *
      * *

      A more complex example illustrates a compound key. The identifier {@code * [Customers].[City].&[San Francisco]&CA&USA.&[cust1234]} * contains four segments as follows: *

        *
      • Segment #0 is QUOTED, name "Customers"
      • *
      • Segment #1 is QUOTED, name "City"
      • *
      • Segment #2 is a {@link Quoting#KEY KEY}. * It has 3 sub-segments: *
          *
        • Sub-segment #0 is QUOTED, name "San Francisco"
        • *
        • Sub-segment #1 is UNQUOTED, name "CA"
        • *
        • Sub-segment #2 is UNQUOTED, name "USA"
        • *
        *
      • *
      • Segment #3 is a KEY. It has 1 sub-segment: *
          *
        • Sub-segment #0 is QUOTED, name "cust1234"
        • *
        *
      • *
      * * @version $Id: IdentifierNode.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class IdentifierNode implements ParseTreeNode { private final List segments; /** * Creates an identifier containing one or more segments. * * @param segments Array of Segments, each consisting of a name and quoting * style */ public IdentifierNode(IdentifierSegment... segments) { if (segments.length < 1) { throw new IllegalArgumentException(); } this.segments = UnmodifiableArrayList.asCopyOf(segments); } /** * Creates an identifier containing a list of segments. * * @param segments List of segments */ public IdentifierNode(List segments) { if (segments.size() < 1) { throw new IllegalArgumentException(); } this.segments = new UnmodifiableArrayList( segments.toArray( new IdentifierSegment[segments.size()])); } public Type getType() { // Can't give the type until we have resolved. throw new UnsupportedOperationException(); } /** * Returns the list of segments which consistitute this identifier. * * @return list of constituent segments */ public List getSegmentList() { return segments; } public ParseRegion getRegion() { // Region is the span from the first segment to the last. return sumSegmentRegions(segments); } /** * Returns a region encompassing the regions of the first through the last * of a list of segments. * * @param segments List of segments * @return Region encompassed by list of segments */ static ParseRegion sumSegmentRegions( final List segments) { return ParseRegion.sum( new AbstractList() { public ParseRegion get(int index) { return segments.get(index).getRegion(); } public int size() { return segments.size(); } }); } /** * Returns a new Identifier consisting of this one with another segment * appended. Does not modify this Identifier. * * @param segment Name of segment * @return New identifier */ public IdentifierNode append(IdentifierSegment segment) { List newSegments = new ArrayList(segments); newSegments.add(segment); return new IdentifierNode(newSegments); } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public void unparse(ParseTreeWriter writer) { writer.getPrintWriter().print(this); } public String toString() { return unparseIdentifierList(segments); } public IdentifierNode deepCopy() { // IdentifierNode is immutable return this; } /** * Parses an MDX identifier string into an * {@link org.olap4j.mdx.IdentifierNode}. * *

      It contains a list of {@link IdentifierSegment segments}, each * of which is a name combined with a description of how the name * was {@link Quoting quoted}. For example, * *

      * parseIdentifier( * "[Customers].USA.[South Dakota].[Sioux Falls].&[1245]") *
      * * returns an IdentifierNode consisting of the following segments: * *
        *
      • NameSegment("Customers", quoted=true), *
      • NameSegment("USA", quoted=false), *
      • NameSegment("South Dakota", quoted=true), *
      • NameSegment("Sioux Falls", quoted=true), *
      • KeySegment( { NameSegment("1245", quoted=true) } ) *
      * * @see #ofNames(String...) * * @param identifier MDX identifier string * * @return Identifier parse tree node * * @throws IllegalArgumentException if the format of the identifier is * invalid */ public static IdentifierNode parseIdentifier(String identifier) { return new IdentifierNode(IdentifierParser.parseIdentifier(identifier)); } /** * Converts an array of quoted name segments into an identifier. * *

      For example, * *

      * IdentifierNode.ofNames("Store", "USA", "CA")
      * * returns an IdentifierNode consisting of the following segments: * *
        *
      • NameSegment("Customers", quoted=true), *
      • NameSegment("USA", quoted=false), *
      • NameSegment("South Dakota", quoted=true), *
      • NameSegment("Sioux Falls", quoted=true), *
      • KeySegment( { NameSegment("1245", quoted=true) } ) *
      * * @see #parseIdentifier(String) * * @param names Array of names * * @return Identifier parse tree node */ public static IdentifierNode ofNames(String... names) { final List list = new ArrayList(); for (String name : names) { list.add(new NameSegment(null, name, Quoting.QUOTED)); } return new IdentifierNode(list); } /** * Returns string quoted in [...]. * *

      For example, "San Francisco" becomes * "[San Francisco]"; "a [bracketed] string" becomes * "[a [bracketed]] string]". * * @param id Unquoted name * @return Quoted name */ static String quoteMdxIdentifier(String id) { StringBuilder buf = new StringBuilder(id.length() + 20); quoteMdxIdentifier(id, buf); return buf.toString(); } /** * Returns a string quoted in [...], writing the results to a * {@link StringBuilder}. * * @param id Unquoted name * @param buf Builder to write quoted string to */ static void quoteMdxIdentifier(String id, StringBuilder buf) { buf.append('['); int start = buf.length(); buf.append(id); Olap4jUtil.replace(buf, start, "]", "]]"); buf.append(']'); } /** * Converts a sequence of identifiers to a string. * *

      For example, {"Store", "USA", * "California"} becomes "[Store].[USA].[California]". * * @param segments List of segments * @return Segments as quoted string */ static String unparseIdentifierList( List segments) { final StringBuilder buf = new StringBuilder(64); for (int i = 0; i < segments.size(); i++) { IdentifierSegment segment = segments.get(i); if (i > 0) { buf.append('.'); } segment.toString(buf); } return buf.toString(); } } // End IdentifierNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/parser/0000755000175000017500000000000011421322450017726 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/mdx/parser/package.html0000644000175000017500000000015311421322450022206 0ustar drazzibdrazzib Provides an API for parsing statements and expressions in the MDX language. olap4j-1.0.1.500/src/org/olap4j/mdx/parser/MdxValidator.java0000644000175000017500000000461511707254776023223 0ustar drazzibdrazzib/* // $Id: MdxValidator.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx.parser; import org.olap4j.OlapException; import org.olap4j.mdx.SelectNode; /** * Validator for the MDX query language. * *

      A validator is reusable but not reentrant: you can call * {@link #validateSelect(org.olap4j.mdx.SelectNode)} several times, but not at * the same time from different threads. * *

      To create a validator, use the * {@link MdxParserFactory#createMdxValidator(org.olap4j.OlapConnection)} * method. * * @see MdxParserFactory * @see MdxParser * * @author jhyde * @version $Id: MdxValidator.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface MdxValidator { /** * Validates an MDX SELECT statement. * *

      The SelectNode representing the SELECT statement may have been * created by an {@link MdxParser}, or it may have been built * programmatically. * *

      If the parse tree is invalid, throws an {@link OlapException}. * *

      If it is valid, returns a parse tree. This parse tree may or may not * be the same parse tree passed as an argument. After validation, you can * ascertain the type of each node of the parse tree by calling its * {@link org.olap4j.mdx.ParseTreeNode#getType()} method. * * @param selectNode Parse tree node representing a SELECT statement * * @return Validated parse tree * * @throws OlapException if node is invalid */ SelectNode validateSelect(SelectNode selectNode) throws OlapException; } // End MdxValidator.java olap4j-1.0.1.500/src/org/olap4j/mdx/parser/MdxParserFactory.java0000644000175000017500000000310211707254776024050 0ustar drazzibdrazzib/* // $Id: MdxParserFactory.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx.parser; import org.olap4j.OlapConnection; /** * Factory for MDX parsers. * * @author jhyde * @version $Id: MdxParserFactory.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface MdxParserFactory { /** * Creates an MDX parser. * * @param connection Connection in which to resolve identifiers * @return MDX parser */ MdxParser createMdxParser(OlapConnection connection); /** * Creates an MDX validator. * * @param connection Connection in which to resolve identifiers * @return MDX validator */ MdxValidator createMdxValidator(OlapConnection connection); } // End MdxParserFactory.java olap4j-1.0.1.500/src/org/olap4j/mdx/parser/MdxParseException.java0000644000175000017500000000454211707254776024226 0ustar drazzibdrazzib/* // $Id: MdxParseException.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx.parser; import org.olap4j.mdx.ParseRegion; /** * Exception thrown by an {@link org.olap4j.mdx.parser.MdxParser} to * indicate an error in parsing. Has a {@link org.olap4j.mdx.ParseRegion}. * * @author jhyde * @version $Id: MdxParseException.java 482 2012-01-05 23:27:27Z jhyde $ */ public class MdxParseException extends RuntimeException { private final ParseRegion region; /** * Creates an MdxParseException with a region of the source code and a * specified cause. * * @param region Region of source code which contains the error * * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public MdxParseException(ParseRegion region, Throwable cause) { super(cause); this.region = region; } /** * Creates an MdxParseException with a region of the source code and a * specified detail message. * * @param region Region of source code which contains the error * * @param message the detail message. The detail message is saved for * later retrieval by the {@link #getMessage()} method. */ public MdxParseException(ParseRegion region, String message) { super(message); this.region = region; } public ParseRegion getRegion() { return region; } } // End MdxParseException.java olap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/0000755000175000017500000000000011504373456020705 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/package.html0000644000175000017500000000013011421322446023147 0ustar drazzibdrazzib Provides a default implementation of the MDX parser API. olap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/StringScanner.java0000644000175000017500000000303211707254776024336 0ustar drazzibdrazzib/* // $Id: StringScanner.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx.parser.impl; /** * Lexical analyzer whose input is a string. * *

      NOTE: This class is not part of the public olap4j API. * * @version $Id: StringScanner.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ class StringScanner extends Scanner { private final String s; private int i; /** * Creates a StringScanner. * * @param s Input string * @param debug Whether to populate debug messages */ StringScanner(String s, boolean debug) { super(debug); this.s = s; i = 0; } protected int getChar() { return (i >= s.length()) ? -1 : s.charAt(i++); } } // End StringScanner.java olap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/DefaultMdxParser.cup0000644000175000017500000015117511707254776024652 0ustar drazzibdrazzib/* // $Id: DefaultMdxParser.cup 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ import java_cup.runtime.*; import java.math.BigDecimal; import java.util.*; import org.olap4j.Axis; import org.olap4j.mdx.*; import org.olap4j.mdx.parser.MdxParseException; // Preliminaries to set up and use the scanner. parser code {: // Generated from $Id: DefaultMdxParser.cup 482 2012-01-05 23:27:27Z jhyde $ Scanner scanner; private String queryString; private DefaultMdxParserImpl.FunTable funTable; /** * Recursively parses an expression. */ ParseTreeNode recursivelyParseExp(String s) { return new DefaultMdxParser().parseExpression( s, false, funTable); } /** * Parses a string to create a {@link SelectNode}. */ SelectNode parseSelect( String queryString, boolean debug, DefaultMdxParserImpl.FunTable funTable) { Symbol parse_tree = null; this.scanner = new StringScanner(queryString, debug); this.queryString = queryString; this.funTable = funTable; try { if (debug) { parse_tree = debug_parse(); } else { parse_tree = parse(); } return (SelectNode) parse_tree.value; } catch (Exception e) { throw new RuntimeException( "Error while parsing MDX statement '" + queryString + "'", e); } finally { this.scanner = null; this.queryString = null; this.funTable = null; } } /** * Parses a string to create an expression. */ ParseTreeNode parseExpression( String queryString, boolean debug, DefaultMdxParserImpl.FunTable funTable) { Symbol parse_tree = null; this.scanner = new PrefixScanner( debug, new StringScanner(queryString, debug), new int[] {DefaultMdxParserSym._VALUE_EXPRESSION}); this.queryString = queryString; this.funTable = funTable; try { if (debug) { parse_tree = debug_parse(); } else { parse_tree = parse(); } return (ParseTreeNode) parse_tree.value; } catch (Exception e) { throw new RuntimeException( "Syntax error while parsing MDX expression '" + queryString + "'", e); } finally { this.scanner = null; this.queryString = null; this.funTable = null; } } /** * Scanner which returns a list of pre-programmed tokens, then switches * to a parent scanner. */ private static class PrefixScanner extends Scanner { private final Scanner parent; private final int tokens[]; private int i; PrefixScanner(boolean debug, Scanner parent, int[] tokens) { super(debug); this.parent = parent; this.tokens = tokens; } public void init() throws java.io.IOException { i = 0; parent.init(); } public Symbol next_token() throws java.io.IOException { if (i < tokens.length) { return new Symbol(tokens[i++], 0, 0, null); } return parent.next_token(); } ParseRegion createRegion(int left, int right) { return parent.createRegion(left, right); } } /** * Creates a {@link SelectNode} object. * Override this function to make your kind of query. */ protected SelectNode newSelect( ParseRegion region, List withList, List axisList, ParseTreeNode from, ParseTreeNode filter, List cellProps) { final AxisNode filterAxis = filter == null ? null : new AxisNode( filter.getRegion(), false, Axis.FILTER, Collections.emptyList(), filter); // sort axes by ordinal Collections.sort( axisList, new Comparator() { public int compare(AxisNode o1, AxisNode o2) { return o1.getAxis().axisOrdinal() - o2.getAxis().axisOrdinal(); } }); return new SelectNode( region, withList, axisList, from, filterAxis, cellProps); } // Override lr_parser methods for NLS. With this error handling scheme, // all errors are fatal. public void report_fatal_error( String message, Object info) throws java.lang.Exception { done_parsing(); try { report_error(message, info); } catch (Throwable e) { throw new RuntimeException( "MDX parser cannot recover from previous error(s)", e); } } // override lr_parser method public void report_error(String message, Object info) { // "Error: %1" throw new RuntimeException("Error: " + message); } // override lr_parser method public void syntax_error(Symbol cur_token) { String s = cur_token.value.toString(); if (cur_token.left != -1) { final ParseRegion region = scanner.createRegion(cur_token.left, cur_token.right); throw new MdxParseException( region, "Syntax error at " + region + ", token '" + s + "'"); } else { throw new RuntimeException( "Syntax error at token '" + s + "'"); } } public void unrecovered_syntax_error(Symbol cur_token) throws java.lang.Exception { report_fatal_error("Couldn't repair and continue parse", cur_token); } /** * Returns whether the given identifier can possibly the name of an operator * with property syntax. * *

      For example, isFunCall("ORDINAL") * returns true because there is a "<Level>.Ordinal" property.

      */ protected boolean isFunCall(String s) { return funTable.isProperty(s); } :}; action code {: ParseRegion createRegion(final int... ordinals) { assert ordinals.length % 2 == 0; return ParseRegion.sum( new Iterable() { public Iterator iterator() { return new Iterator() { int i = 0; public boolean hasNext() { return i < ordinals.length; } public ParseRegion next() { return parser.scanner.createRegion( ordinals[i++], ordinals[i++]); } public void remove() { throw new UnsupportedOperationException(); } }; } } ); } static List emptyList(List list) { if (list == null) { return Collections.emptyList(); } return list; } :}; init with {: scanner.init(); :}; scan with {: return scanner.next_token(); :}; // Terminals (tokens returned by the scanner). // a. Keywords. terminal AND, AS, AXIS, CASE, CAST, CELL, CHAPTERS, COLUMNS, DIMENSION, ELSE, EMPTY, END, FROM, IN, IS, MATCHES, MEMBER, NON, NOT, NULL, ON, OR, PAGES, PROPERTIES, ROWS, SECTIONS, SELECT, SET, THEN, WHEN, WHERE, XOR, WITH, _VALUE_EXPRESSION; // b. Symbols terminal ASTERISK, // * COLON, // : COMMA, // , CONCAT, // || DOT, // . EQ, // = GE, // >= GT, // > LBRACE, // { LE, // <= LPAREN, // ( LT, // < MINUS, // - NE, // <> PLUS, // + RBRACE, // } RPAREN, // ) SOLIDUS; // / // c. Typed terminals terminal BigDecimal NUMBER; terminal String ID; terminal String QUOTED_ID; terminal String AMP_QUOTED_ID; terminal String AMP_UNQUOTED_ID; terminal String STRING; terminal String FORMULA_STRING; terminal String UNKNOWN; // a token the lexer doesn't like! // Non terminals non terminal AxisNode axis_specification; non terminal ParseTreeNode case_expression, cube_specification_or_select_statement, else_clause_opt, expression, expression_or_empty, factor, filter_specification, term, term2, term3, term4, term5, value_expression, value_expression_opt, value_expression_primary, where_clause_opt; non terminal ParseTreeNode select_statement, single_formula_specification, statement; non terminal IdentifierNode cell_property, compound_id, cube_name, cube_specification, member_name, set_name; non terminal Axis.Standard axis_name; non terminal String comp_op, keyword; non terminal IdentifierSegment identifier, key_identifier, quoted_identifier, unquoted_identifier, amp_identifier, amp_quoted_identifier, amp_unquoted_identifier; non terminal List amp_identifier_list; non terminal WithMemberNode member_specification; non terminal WithSetNode set_specification; non terminal PropertyValueNode member_property_definition; non terminal cell_opt, dimension_opt, property, unsigned_integer; non terminal Boolean non_empty_opt; non terminal List axis_specification_list, axis_specification_list_opt, cell_props, cell_props_opt, comma_member_property_def_list_opt, dim_props, dim_props_opt, exp_list, exp_list_opt, formula_specification, member_property_def_list, property_list, cell_property_list, when_list, with_formula_specification_opt; non terminal ParseTreeNode[] when_clause; non terminal BigDecimal axis_number; // Start symbol start with statement; // ---------------------------------------------------------------------------- // Elements // // // ::= | quoted_identifier ::= QUOTED_ID:i {: ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.QUOTED); :} ; unquoted_identifier ::= ID:i {: ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.UNQUOTED); :} | keyword:i {: ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.UNQUOTED); :} ; // for example '&foo&[1]&bar' in '[x].&foo&[1]&bar.[y]' key_identifier ::= amp_identifier_list:list {: RESULT = new KeySegment(list); :} ; amp_identifier_list ::= amp_identifier:i {: RESULT = new ArrayList(); RESULT.add(i); :} | amp_identifier_list:list amp_identifier:i {: list.add(i); RESULT = list; :} ; amp_identifier ::= amp_quoted_identifier | amp_unquoted_identifier ; amp_quoted_identifier ::= AMP_QUOTED_ID:i {: ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.QUOTED); :} ; amp_unquoted_identifier ::= AMP_UNQUOTED_ID:i {: ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.UNQUOTED); :} ; identifier ::= unquoted_identifier | quoted_identifier | key_identifier ; // a keyword (unlike a reserved word) can be converted back into an // identifier in some contexts keyword ::= DIMENSION {: RESULT = "Dimension"; :} | PROPERTIES {: RESULT = "Properties"; :} ; compound_id ::= identifier:i {: RESULT = new IdentifierNode(i); :} | compound_id:hd DOT identifier:tl {: RESULT = hd.append(tl); :} ; // // ::= [{ | // | }...] // // ::= // { | } // [{ | }...] // // // ::= // // ::= // // ::= end_delimiter> // // ::= !! // // ::= [ [ [ ] ] [].] // cube_name ::= compound_id ; // // ::= // // ::= // // ::= // // ::= [.] // | [[.]< dimension_name>.] // jhyde: Need more lookahead for this to work... just use id in place of // dim_hier. // dim_hier ::= id; // // ::= // | .DIMENSION // | .DIMENSION // | .DIMENSION // // ::= // | < member>.HIERARCHY // | .HIERARCHY // // ::= [.]< identifier> // | .LEVELS() // | .LEVEL // // Note: The first production is for the case when named levels are // supported. The second production is for the case when named levels are not // supported. // // // ::= [.] // | . // | . // | // // Note: The . recognizes the fact that members may // sometimes need to be qualified by their parent names. For example, // "Portland" is a city in Oregon, and also in Maine. So a reference to // Portland will be either Oregon.Portland or Maine.Portland. // // // ::= | // // ::= CATALOG_NAME // | SCHEMA_NAME // | CUBE_NAME // | DIMENSION_UNIQUE_NAME // | HIERARCHY_UNIQUE_NAME // | LEVEL_UNIQUE_NAME // | LEVEL_NUMBER // | MEMBER_UNIQUE_NAME // | MEMBER_NAME // | MEMBER_TYPE // | MEMBER_GUID // | MEMBER_CAPTION // | MEMBER_ORDINAL // | CHILDREN_CARDINALITY // | PARENT_LEVEL // | PARENT_UNIQUE_NAME // | PARENT_COUNT // | DESCRIPTION // // ::= . // | . // | . // // Note: The three productions recognize the fact that a property can apply to // all the members of a dimension, or all the members of a level, or just to a // member. // // // ::= // | ( [, ...]) // | // // Note: Each member must be from a different dimension or from a different // hierarchy. // // // ::= : // // Note: Each member must be from the same hierarchy and the same level. // // // | // | [| [, |...]] // // Note: Duplicates (if any) are always retained when specifying sets in this // fashion. // // // | () // // ::= { // // ::= } // // ::= [ // // ::= ] // // ::= _ // // ::= a | b | c | ...| z | A | B | C | ... | Z // // ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 // // Leveling Rules for Elements // // The ability to qualify a cube name by one or more of , // , or is optional. Consumers can check the value // of the property MDPROP_MDX_OBJQUALIFICATION to see whether a provider // supports cube qualification. // // // The ability to qualify a dimension name by a cube name is // optional. Consumers can check the value of the property // MDPROP_MDX_OBJQUALIFICATION to see whether a provider supports dimension // qualification. // // // The ability to qualify a hierarchy name by a dimension name or by cube name // and dimension name is optional. Consumers can check the value of the // property MDPROP_MDX_OBJQUALIFICATION to see whether a provider supports // hierarchy qualification. // // // The provider need support only one of the two productions for . If it // supports // // ::= [.] // // then the ability to qualify by is optional. // // Consumers can check the value of the property MDPROP_NAMED_LEVELS to see if // the provider supports named levels. If it does, then the consumer can check // MDPROP_MDX_OBJQUALIFICATION to see whether named levels can be qualified by // . // // The ability to qualify a member by a level, a member, or is // optional. Consumers can check the value of the property // MDPROP_MDX_OBJQUALIFICATION to see whether a provider supports member // qualification. // // Note: Several leveling rules above make it optional to qualify // multidimensional schema object names. However, this does not imply that the // ability to generate unique names for members, levels, dimensions, and // hierarchies is optional. Providers are required to furnish unique names in // the schema rowsets for these objects. If providers generate unique names by // means other than qualification, then the ability to qualify is optional. For // more information, see 'Provider Implementation Considerations for Unique // Names' in Chapter 2. // // // ---------------------------------------------------------------------------- // // // Expressions // // Note: The syntax of is generally the same as SQL-92, // subclause 6.11, . Differences are: // // [.VALUE], [.VALUE], and are new // values for . // // // There are new values for , mainly for statistical // analysis. // // // The BNF for , , and // have been shortened by eliminating several // intermediate nonterminals. // // ::= // | // // ::= // | { | } value_expression ::= term5 | value_expression:x OR term5:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "OR", Syntax.Infix, x, y); :} | value_expression:x XOR term5:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "XOR", Syntax.Infix, x, y); :} ; term5 ::= term4 | term5:x AND term4:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "AND", Syntax.Infix, x, y); :} ; term4 ::= term3 | NOT:not term4:p {: ParseRegion region = createRegion(notleft, pright); RESULT = new CallNode(region, "NOT", Syntax.Prefix, p); :} ; term3 ::= term2 | term3:x comp_op:op term2:y {: // e.g. "1 < 5" ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, op, Syntax.Infix, x, y); :} | // We expect a shift-reduce conflict here, because NULL is a literal and // so is a valid argument to the IS operator. JavaCUP resolves the // conflict by shifting, which is what we want. Compile with expect=61 // to ignore the conflicts and continue. term3:x IS NULL:n {: ParseRegion region = createRegion(xleft, nright); RESULT = new CallNode(region, "IS NULL", Syntax.Postfix, x); :} | term3:x IS term2:y {: // e.g. "x IS y"; but "x IS NULL" is handled elsewhere ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "IS", Syntax.Infix, x, y); :} | term3:x IS EMPTY:empty {: ParseRegion region = createRegion(xleft, emptyright); RESULT = new CallNode(region, "IS EMPTY", Syntax.Postfix, x); :} | term3:x MATCHES term2:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "MATCHES", Syntax.Infix, x, y); :} | term3:x NOT MATCHES term2:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode( region, "NOT", Syntax.Prefix, new CallNode(region, "MATCHES", Syntax.Infix, x, y)); :} | term3:x IN term2:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "IN", Syntax.Infix, x, y); :} | term3:x NOT IN term2:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode( region, "NOT", Syntax.Prefix, new CallNode(region, "IN", Syntax.Infix, x, y)); :} ; term2 ::= term | term2:x PLUS term:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "+", Syntax.Infix, x, y); :} | term2:x MINUS term:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "-", Syntax.Infix, x, y); :} | term2:x CONCAT term:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "||", Syntax.Infix, x, y); :} ; // // ::= | { | } term ::= factor | term:x ASTERISK factor:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "*", Syntax.Infix, x, y); :} | term:x SOLIDUS factor:y {: ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "/", Syntax.Infix, x, y); :} ; // // ::= [] // factor ::= value_expression_primary | PLUS value_expression_primary:p {: RESULT = p; :} | MINUS:minus value_expression_primary:p {: ParseRegion region = createRegion(minusleft, pright); RESULT = new CallNode(region, "-", Syntax.Prefix, p); :} ; // ::= + | - // // ::= + // // ::= - // // ::= * // // ::= / // // ::= // | // // Note: The data type of in the above production // shall be numeric. // // // ::= // | () // | // | [.][.VALUE] // | [.VALUE] // | value_expression_primary ::= STRING:s {: ParseRegion region = createRegion(sleft, sright); RESULT = LiteralNode.createString(region, s); :} | NUMBER:d {: ParseRegion region = createRegion(dleft, dright); RESULT = LiteralNode.createNumeric(region, d, false); :} | identifier:i {: RESULT = new IdentifierNode(i); :} | value_expression_primary:i DOT unquoted_identifier:j {: if (i instanceof IdentifierNode && !parser.isFunCall(j.getName())) { RESULT = ((IdentifierNode) i).append(j); } else { ParseRegion region = createRegion(ileft, jright); RESULT = new CallNode(region, j.getName(), Syntax.Property, i); } :} | value_expression_primary:i DOT quoted_identifier:j {: if (i instanceof IdentifierNode) { RESULT = ((IdentifierNode) i).append(j); } else { ParseRegion region = createRegion(ileft, jright); RESULT = new CallNode( region, j.getName(), Syntax.QuotedProperty, i); } :} | value_expression_primary:i DOT key_identifier:j {: if (i instanceof IdentifierNode) { RESULT = ((IdentifierNode) i).append(j); } else { ParseRegion region = createRegion(ileft, jright); RESULT = new CallNode( region, j.getName(), Syntax.AmpersandQuotedProperty, i); } :} | value_expression_primary:i DOT identifier:j LPAREN exp_list_opt:lis RPAREN:rparen {: lis.add(0, i); ParseRegion region = createRegion(ileft, rparenright); RESULT = new CallNode(region, j.getName(), Syntax.Method, lis); :} | identifier:i LPAREN exp_list_opt:lis RPAREN:rparen {: ParseRegion region = createRegion(ileft, rparenright); RESULT = new CallNode(region, i.getName(), Syntax.Function, lis); :} | CAST:cast LPAREN expression:e AS identifier:t RPAREN:rparen {: LiteralNode symbol = LiteralNode.createSymbol(t.getRegion(), t.getName()); ParseRegion region = createRegion(castleft, rparenright); RESULT = new CallNode(region, "CAST", Syntax.Cast, e, symbol); :} | LPAREN:lparen exp_list:lis RPAREN:rparen {: // Whereas ([Sales],[Time]) and () are tuples, ([Sales]) and (5) // are just expressions. ParseRegion region = createRegion(lparenleft, rparenright); RESULT = new CallNode(region, "()", Syntax.Parentheses, lis); :} | LBRACE:lbrace exp_list_opt:lis RBRACE:rbrace {: // set built from sets/tuples ParseRegion region = createRegion(lbraceleft, rbraceright); RESULT = new CallNode(region, "{}", Syntax.Braces, lis); :} | NULL:n {: ParseRegion region = createRegion(nleft, nright); RESULT = LiteralNode.createNull(region); :} | case_expression ; case_expression ::= CASE:kase value_expression_opt:x when_list:y else_clause_opt:z END {: List v = new ArrayList(); if (x != null) { v.add(x); } for (int i = 0; i < y.size(); i++) { ParseTreeNode[] exps = (ParseTreeNode[]) y.get(i); assert exps.length == 2; v.add(exps[0]); v.add(exps[1]); } if (z != null) { v.add(z); } ParseRegion region = createRegion(kaseleft, zright); if (x == null) { RESULT = new CallNode(region, "_CaseTest", Syntax.Case, v); } else { RESULT = new CallNode(region, "_CaseMatch", Syntax.Case, v); } :} ; value_expression_opt ::= /* empty */ | value_expression ; when_list ::= /* empty */ {: RESULT = new ArrayList(); :} | when_list:x when_clause:y {: RESULT = x; x.add(y); :} ; when_clause ::= WHEN value_expression:x THEN value_expression:y {: RESULT = new ParseTreeNode[] {x, y}; :} ; else_clause_opt ::= /* empty */ | ELSE value_expression:x {: RESULT = x; :} ; // // ::= | // // ::= iif(, , ) // // ::= // // ::= // // ::= | | // // ::= CASE // ... // [] // END // // ::= CASE // ... // [] // END // // ::= WHEN THEN // // ::= WHEN THEN // // ::= ELSE // // ::= // // ::= // // ::= // // ::= COALESCEEMPTY ( // {, }...) // // ::= [] // // ::= // | // // ::= [.] // | . // | . // // ::= {}... // // ::= E // // ::= < exact_numeric_literal> // // ::= [] // // ::= // | // // // // Note: The data type of in the above production // shall be a character string. // // // ::= [...] // // // ::= | // // ::= !! // // // ::= // // ::= ' // // ::= || // // Leveling Rules for Expressions // // The following productions for are optional: // // The ability to qualify [.VALUE] by in a value expression // primary is optional. Consumers can check the value of the property // MDPROP_MDX_OUTERREFERENCE to see whether a provider supports this feature. // // // [.VALUE]. Consumers can check the value of the property // MDPROP_MDX_QUERYBYPROPERTY to see whether a provider supports this feature. // // // , . Consumers can check the value of the // property MDPROP_MDX_CASESUPPORT to see whether a provider supports this // feature. // // ---------------------------------------------------------------------------- // Search Condition // // ::= // | {OR | XOR} // // ::= | AND // // ::= [NOT] // // ::= // | ISEMPTY() // | IS EMPTY // | () // ::= // | // | // | // | // | // "IS" is not a comp_op because of conflict with " IS EMPTY" comp_op ::= EQ {: RESULT = "="; :} | NE {: RESULT = "<>"; :} | LT {: RESULT = "<"; :} | GT {: RESULT = ">"; :} | LE {: RESULT = "<="; :} | GE {: RESULT = ">="; :} ; // // ::= = // // ::= <> // // ::= > // // ::= < // // ::= >= // // ::= <= // // Leveling Rules for Search Condition // // If in a value is a string value // expression, then support for values other than // and is optional. Consumers can check the value of the // property MDPROP_MDX_STRING_COMPOP to see whether a provider supports this // feature. // ---------------------------------------------------------------------------- // Set Value Expression // // ::= // // Note: denotes an integer argument. If an arbitrary // appears here, then it is truncated to the nearest // integer. // // // ::= // // ::= .MEMBERS // | .MEMBERS // | .CHILDREN // | BOTTOMCOUNT(, // [, ]) // | BOTTOMPERCENT(, , // ) // | BOTTOMSUM(, , // ) // | CROSSJOIN(, ) // | DESCENDANTS(, [,]) // // Note: In the absence of explicit specification, SELF is the // default. // // | DISTINCT() // | DRILLDOWNLEVEL( [, ]]) // | DRILLDOWNLEVELBOTTOM(, // [,[] [, ]]) // | DRILLDOWNLEVELTOP(, [, [] // [, ]]) // | DRILLDOWNMEMBER(, [, RECURSIVE]) // | DRILLDOWNMEMBERBOTTOM(, , // [, ][, RECURSIVE]]) // | DRILLDOWNMEMBERTOP(, , // [, [][, RECURSIVE]]) // | DRILLUPLEVEL([, ]]) // | DRILLUPMEMBER(, ) // | EXCEPT(, [, ALL]) // | EXTRACT(, [, ...]) // | FILTER(, ) // | GENERATE(, [, ALL]) // | HIERARCHIZE() // | INTERSECT(, [, ALL]) // | LASTPERIODS( [, ]) // | MTD([]) // | ORDER(, // [, ASC | DESC | BASC | BDESC]) // // Note: In the absence of explicit specification, ASC is the default. // // // | PERIODSTODATE([[, ]]) // | QTD([]) // | TOGGLEDRILLSTATE(, [, RECURSIVE]) // // Note: With the exception of CROSSJOIN, all set functions that take more than // one argument require that the two set arguments have tuples of the // same dimensionality. // // // | TOPCOUNT(, // [, ]) // | TOPPERCENT(, , // ) // | TOPSUM(, , // ) // | UNION(, [, ALL]) // | WTD([]) // | YTD() // // ::= SELF // | AFTER // | BEFORE // | BEFORE_AND_AFTER // | SELF_AND_AFTER // | SELF_AND_BEFORE // | SELF_BEFORE_AFTER // // ---------------------------------------------------------------------------- // Member Value Expression // // ::= .{PARENT | FIRSTCHILD | LASTCHILD // | PREVMEMBER | NEXTMEMBER} // | .LEAD() // | .LAG() // // Note: LAG() is the same as LEAD(-) // // // | .{FIRSTSIBLING | LASTSIBLING} // | .[CURRENTMEMBER] // | .DEFAULTMEMBER // | .DEFAULTMEMBER // | ANCESTOR(, ) // | CLOSINGPERIOD([[, ]) // | COUSIN(, ) // | OPENINGPERIOD([[, ]) // | PARALLELPERIOD([[, // [, ]]]) expression ::= expression:x COLON value_expression:y {: // range yields set ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, ":", Syntax.Infix, x, y); :} | value_expression ; expression_or_empty ::= expression | /* empty */ {: final ParseRegion region = createRegion(0, 0); RESULT = new CallNode(region, "", Syntax.Empty); :} ; exp_list_opt ::= /* empty */ {: RESULT = new LinkedList(); :} | exp_list ; exp_list ::= expression:e {: RESULT = new LinkedList(); RESULT.add(e); :} | expression_or_empty:e COMMA exp_list:list {: list.add(0, e); RESULT = list; :} ; // // Leveling Rules for Member Value Expression // // The following member functions are optional: COUSIN, PARALLELPERIOD, // OPENINGPERIOD, CLOSINGPERIOD. Consumers can check the value of the property // MDPROP_MDX_MEMBER_FUNCTIONS to see whether a provider supports this feature. // // // * Tuple Value Expression // // ::= .CURRENTMEMBER // | [.ITEM]( // [, ...] | ) // // // * Numeric Value Function // // ::= // AGGREGATE( [, ]) // | AVG([, ]) // | CORRELATION( [, ] // [, ]) // | COVARIANCE([, // [, ]) // | COUNT([, INCLUDEEMPTY]) // | LINREGINTERCEPT([, // // // Leveling Rules for Numeric Value Function // // The following numeric functions are optional: MEDIAN, VAR, STDEV, RANK, // AGGREGATE, COVARIANCE, CORRELATION, LINREGSLOPE, LINREGVARIANCE, LINREGR2, // LINREGPOINT. Consumers can check the value of the property // MDPROP_MDX_NUMERIC_FUNCTIONS to see whether a provider supports this // feature. // // ---------------------------------------------------------------------------- // MDX Statement // // ::= // | // | // // ::= [WITH ] // SELECT [ // [, ...]] // FROM [] // WHERE [] // [] // | // [WITH ] // SELECT [ // [, ...]] // FROM ( select_statement ) // WHERE [] // [] // jhyde: The above is wrong... you can omit 'WHERE'. statement ::= select_statement | _VALUE_EXPRESSION value_expression:e {: RESULT = (ParseTreeNode) e; :} ; cube_specification_or_select_statement ::= cube_specification | LPAREN select_statement:s RPAREN {: RESULT = s; :} ; select_statement ::= with_formula_specification_opt:f SELECT:select axis_specification_list_opt:a FROM cube_specification_or_select_statement:c where_clause_opt:w cell_props_opt:cp {: ParseRegion region = createRegion(selectleft, selectright); RESULT = parser.newSelect(region, f, a, c, w, cp); :}; with_formula_specification_opt ::= /* empty */ {: RESULT = new LinkedList(); :} | WITH formula_specification:f {: RESULT = f; :} ; axis_specification_list_opt ::= /* empty */ {: RESULT = new LinkedList(); :} | axis_specification_list ; axis_specification_list ::= axis_specification:i {: RESULT = new LinkedList(); RESULT.add(i); :} | axis_specification:e COMMA axis_specification_list:list {: list.add(0, e); RESULT = list; :} ; where_clause_opt ::= /* empty */ | WHERE filter_specification:s {: RESULT = s; :}; cell_props_opt ::= /* empty */ {: RESULT = new LinkedList(); :} | cell_props; // // ::= // [...] // formula_specification ::= single_formula_specification:e {: RESULT = new LinkedList(); RESULT.add(e); :} | single_formula_specification:hd formula_specification:tl {: tl.add(0, hd); RESULT = tl; :} ; // ::= // | // single_formula_specification ::= member_specification | set_specification ; // // ::= MEMBER AS // [, ] // [, ...] member_specification ::= MEMBER:member member_name:m AS FORMULA_STRING:s comma_member_property_def_list_opt:l {: ParseTreeNode e = parser.recursivelyParseExp(s); ParseRegion region = createRegion(memberleft, sright); RESULT = new WithMemberNode(region, m, e, l); :} | MEMBER:member member_name:m AS value_expression:e comma_member_property_def_list_opt:l {: ParseRegion region = createRegion(memberleft, eright); RESULT = new WithMemberNode(region, m, e, l); :} ; comma_member_property_def_list_opt ::= /* empty */ {: RESULT = new LinkedList(); :} | COMMA member_property_def_list:l {: RESULT = l; :} ; member_property_def_list ::= member_property_definition:m {: RESULT = new LinkedList(); RESULT.add(m); :} | member_property_definition:hd COMMA member_property_def_list:tl {: RESULT = tl; RESULT.add(0, hd); :} ; // // ::= . // | .. // member_name ::= compound_id; // // Note: // // The identifier defines a new member. The qualification member has enough // information to specify the dimension, and the level in the dimension that // this new member should be on. // // // If is part of a member specification that appears in a create // formula statement or is part of a drop formula statement, then it must be // qualified by a cube name, as in the second production above. // // ::= SOLVE_ORDER = // // ::= = member_property_definition ::= identifier:id EQ value_expression:e {: ParseRegion region = createRegion(idleft, eright); RESULT = new PropertyValueNode(region, id.getName(), e); :} ; // // Note: Since the property definition appears in the context of a member // definition, there is enough information to associate the identifier (which // is the property name) in the above production with a member. // // // ::= SET AS set_specification ::= SET:set set_name:n AS FORMULA_STRING:s {: ParseTreeNode e = parser.recursivelyParseExp(s); ParseRegion region = createRegion(setleft, sright); RESULT = new WithSetNode(region, n, e); :} | SET:set set_name:n AS expression:e {: ParseRegion region = createRegion(setleft, eright); RESULT = new WithSetNode(region, n, e); :} ; // // ::= | . set_name ::= compound_id ; // // Note: If is part of a set specification that appears in a create // formula statement or is part of a drop formula statement, then it must be // qualified by a cube name, as in the second production above. // // // ::= [NON EMPTY] [] ON axis_specification ::= non_empty_opt:b expression:s dim_props_opt:dp ON axis_name:a {: ParseRegion region = createRegion( bleft, bright, sleft, sright, dpleft, dpright, aleft, aright); RESULT = new AxisNode(region, b, a, emptyList(dp), s); :} | non_empty_opt:b expression:s dim_props_opt:dp ON axis_number:n {: double d = n.doubleValue(); int index = (int)d; // AxisOrdinal values go from -2 to 4 for standard axis, but higher // ordinals are allowed. The negative values represent // special cases, so are ignored. if (index < 0 || index != d) { throw new MdxParseException( createRegion(nleft, nright), "Invalid axis specification. The axis number must be a " + "non-negative integer, but it was " + d + "."); } Axis axis = Axis.Factory.forOrdinal(index); ParseRegion region = createRegion( bleft, bright, sleft, sright, dpleft, dpright, nleft, nright); RESULT = new AxisNode(region, b, axis, emptyList(dp), s); :} ; non_empty_opt ::= /* empty */ {: RESULT = Boolean.FALSE; :} | NON EMPTY {: RESULT = Boolean.TRUE; :} ; dim_props_opt ::= /* empty */ | dim_props ; // // ::= COLUMNS // | ROWS // | PAGES // | CHAPTERS // | SECTIONS // | AXIS() axis_name ::= COLUMNS {: RESULT = Axis.COLUMNS; :} | ROWS {: RESULT = Axis.ROWS; :} | PAGES {: RESULT = Axis.PAGES; :} | SECTIONS {: RESULT = Axis.SECTIONS; :} | CHAPTERS {: RESULT = Axis.CHAPTERS; :} ; axis_number ::= NUMBER | AXIS LPAREN NUMBER:n RPAREN {: RESULT = n; :} ; // // ::= [DIMENSION] PROPERTIES [, ...] dim_props ::= dimension_opt PROPERTIES property_list:pl {: RESULT = pl; :} ; dimension_opt ::= /* empty */ | DIMENSION ; property_list ::= property:p {: RESULT = new LinkedList(); RESULT.add(p); :} | property:p COMMA property_list:pl {: pl.add(0, p); RESULT = pl; :} ; property ::= compound_id ; // // ::= [] [, ] // jhyde: In this implementation, you must supply EXACTLY one cube. cube_specification ::= cube_name; // // ::= { | } filter_specification ::= expression; // // ::= [CELL] PROPERTIES [, ...] cell_props ::= cell_opt PROPERTIES cell_property_list:p1 {: RESULT = p1; :} ; cell_opt ::= /* empty */ | CELL ; cell_property_list ::= cell_property:p {: RESULT = new LinkedList(); RESULT.add(p); :} | cell_property:p COMMA cell_property_list:p1 {: p1.add(0, p); RESULT = p1; :} ; // ::= FORMAT_STRING // | FORMATTED_VALUE // | FORE_COLOR // | BACK_COLOR // | FONT_NAME // | FONT_SIZE // | FONT_FLAGS // | CELL_ORDINAL // | VALUE cell_property ::= compound_id; // // ::= CREATE [] // // ::= // | // // ::= DROP MEMBER // [, ...] // // ::= DROP SET [, ...] // // := GLOBAL | SESSION // // Leveling Rules for MDX Statement // // Support for is optional. Consumers can check the // value of the property MDPROP_MDX_FORMULAS to see whether a provider supports // this feature. // // // Support for in is optional. Consumers can check // the value of the property MDPROP_MDX_SLICER to see whether a provider // supports this feature. // // // Support for more than one cube name in is // optional. Support for having no cube name in the FROM clause (that is, the // cube is implicitly defined by the axis and filter dimensions) is also // optional. Consumers can check the value of the property MDPROP_MDX_JOINCUBES // to see whether a provider supports this feature. // // // The axis names CHAPTERS and SECTIONS are optional. Consumers can check the // value of the property MDPROP_AXES to see whether a provider supports this // feature. // // // Support for > 2 in the AXIS() function is optional. Consumers // can check the value of the property MDPROP_AXES to see whether a provider // supports this feature. // // // Support for is optional. Consumers can check the // value of the property MDPROP_MDX_FORMULAS to see whether a provider supports // this feature. // // // Support for of GLOBAL is optional. Consumers can check the value of // the property MDPROP_MDX_FORMULAS to see whether a provider supports this // feature. // // End DefaultMdxParser.cup olap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/DefaultMdxParserSym.java0000644000175000017500000000534211707500602025445 0ustar drazzibdrazzib //---------------------------------------------------- // The following code was generated by CUP v0.10k // Tue Jan 24 11:01:37 EST 2012 //---------------------------------------------------- package org.olap4j.mdx.parser.impl; /** CUP generated interface containing symbol constants. */ public interface DefaultMdxParserSym { /* terminals */ public static final int CAST = 6; public static final int WHEN = 31; public static final int WITH = 34; public static final int GE = 42; public static final int CONCAT = 39; public static final int ASTERISK = 36; public static final int EMPTY = 12; public static final int DIMENSION = 10; public static final int _VALUE_EXPRESSION = 35; public static final int XOR = 33; public static final int CASE = 5; public static final int PAGES = 24; public static final int LPAREN = 46; public static final int QUOTED_ID = 56; public static final int MINUS = 48; public static final int ROWS = 26; public static final int WHERE = 32; public static final int RPAREN = 52; public static final int NOT = 20; public static final int IS = 16; public static final int AND = 2; public static final int LT = 47; public static final int IN = 15; public static final int OR = 23; public static final int COMMA = 38; public static final int NON = 19; public static final int ON = 22; public static final int SELECT = 28; public static final int PLUS = 50; public static final int FORMULA_STRING = 60; public static final int MEMBER = 18; public static final int ID = 55; public static final int DOT = 40; public static final int LE = 45; public static final int EOF = 0; public static final int MATCHES = 17; public static final int error = 1; public static final int NULL = 21; public static final int NUMBER = 54; public static final int UNKNOWN = 61; public static final int EQ = 41; public static final int FROM = 14; public static final int SOLIDUS = 53; public static final int AMP_UNQUOTED_ID = 58; public static final int COLON = 37; public static final int LBRACE = 44; public static final int ELSE = 11; public static final int PROPERTIES = 25; public static final int SECTIONS = 27; public static final int COLUMNS = 9; public static final int AXIS = 4; public static final int RBRACE = 51; public static final int THEN = 30; public static final int NE = 49; public static final int END = 13; public static final int STRING = 59; public static final int AMP_QUOTED_ID = 57; public static final int CELL = 7; public static final int AS = 3; public static final int GT = 43; public static final int CHAPTERS = 8; public static final int SET = 29; } olap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/DefaultMdxParser.java0000644000175000017500000061724311707500602024765 0ustar drazzibdrazzib //---------------------------------------------------- // The following code was generated by CUP v0.10k // Tue Jan 24 11:01:37 EST 2012 //---------------------------------------------------- package org.olap4j.mdx.parser.impl; import java_cup.runtime.*; import java.math.BigDecimal; import java.util.*; import org.olap4j.Axis; import org.olap4j.mdx.*; import org.olap4j.mdx.parser.MdxParseException; /** CUP v0.10k generated parser. * @version Tue Jan 24 11:01:37 EST 2012 */ public class DefaultMdxParser extends java_cup.runtime.lr_parser { /** Default constructor. */ public DefaultMdxParser() {super();} /** Constructor which sets the default scanner. */ public DefaultMdxParser(java_cup.runtime.Scanner s) {super(s);} /** Production table. */ protected static final short _production_table[][] = unpackFromStrings(new String[] { "\000\211\000\002\002\004\000\002\042\003\000\002\043" + "\003\000\002\043\003\000\002\041\003\000\002\047\003" + "\000\002\047\004\000\002\044\003\000\002\044\003\000" + "\002\045\003\000\002\046\003\000\002\040\003\000\002" + "\040\003\000\002\040\003\000\002\037\003\000\002\037" + "\003\000\002\030\003\000\002\030\005\000\002\031\003" + "\000\002\020\003\000\002\020\005\000\002\020\005\000" + "\002\017\003\000\002\017\005\000\002\016\003\000\002" + "\016\004\000\002\015\003\000\002\015\005\000\002\015" + "\005\000\002\015\005\000\002\015\005\000\002\015\005" + "\000\002\015\006\000\002\015\005\000\002\015\006\000" + "\002\014\003\000\002\014\005\000\002\014\005\000\002" + "\014\005\000\002\013\003\000\002\013\005\000\002\013" + "\005\000\002\011\003\000\002\011\004\000\002\011\004" + "\000\002\022\003\000\002\022\003\000\002\022\003\000" + "\002\022\005\000\002\022\005\000\002\022\005\000\002" + "\022\010\000\002\022\006\000\002\022\010\000\002\022" + "\005\000\002\022\005\000\002\022\003\000\002\022\003" + "\000\002\004\007\000\002\021\002\000\002\021\003\000" + "\002\075\002\000\002\075\004\000\002\077\006\000\002" + "\006\002\000\002\006\004\000\002\036\003\000\002\036" + "\003\000\002\036\003\000\002\036\003\000\002\036\003" + "\000\002\036\003\000\002\007\005\000\002\007\003\000" + "\002\010\003\000\002\010\002\000\002\070\002\000\002" + "\070\003\000\002\067\003\000\002\067\005\000\002\026" + "\003\000\002\026\004\000\002\005\003\000\002\005\005" + "\000\002\024\011\000\002\076\002\000\002\076\004\000" + "\002\061\002\000\002\061\003\000\002\060\003\000\002" + "\060\005\000\002\023\002\000\002\023\004\000\002\063" + "\002\000\002\063\003\000\002\071\003\000\002\071\004" + "\000\002\025\003\000\002\025\003\000\002\050\007\000" + "\002\050\007\000\002\064\002\000\002\064\004\000\002" + "\072\003\000\002\072\005\000\002\033\003\000\002\052" + "\005\000\002\051\006\000\002\051\006\000\002\034\003" + "\000\002\003\007\000\002\003\007\000\002\057\002\000" + "\002\057\004\000\002\066\002\000\002\066\003\000\002" + "\035\003\000\002\035\003\000\002\035\003\000\002\035" + "\003\000\002\035\003\000\002\100\003\000\002\100\006" + "\000\002\065\005\000\002\054\002\000\002\054\003\000" + "\002\073\003\000\002\073\005\000\002\055\003\000\002" + "\032\003\000\002\012\003\000\002\062\005\000\002\053" + "\002\000\002\053\003\000\002\074\003\000\002\074\005" + "\000\002\027\003" }); /** Access to production table. */ public short[][] production_table() {return _production_table;} /** Parse-action table. */ protected static final short[][] _action_table = unpackFromStrings(new String[] { "\000\317\000\010\036\uffac\044\005\045\007\001\002\000" + "\004\002\uffb1\001\002\000\006\024\274\037\272\001\002" + "\000\004\002\266\001\002\000\042\007\055\010\033\014" + "\044\026\026\027\061\033\035\056\032\060\031\062\053" + "\064\022\070\042\071\034\072\050\073\037\074\045\075" + "\036\001\002\000\004\036\011\001\002\000\046\007\uff91" + "\010\uff91\014\uff91\020\uffaa\025\015\026\uff91\027\uff91\033" + "\uff91\056\uff91\060\uff91\062\uff91\064\uff91\070\uff91\071\uff91" + "\072\uff91\073\uff91\074\uff91\075\uff91\001\002\000\004\020" + "\237\001\002\000\042\007\055\010\033\014\044\026\026" + "\027\061\033\035\056\032\060\031\062\053\064\022\070" + "\042\071\034\072\050\073\037\074\045\075\036\001\002" + "\000\006\020\uffa8\050\020\001\002\000\004\016\017\001" + "\002\000\004\020\uffa9\001\002\000\042\007\uff90\010\uff90" + "\014\uff90\026\uff90\027\uff90\033\uff90\056\uff90\060\uff90\062" + "\uff90\064\uff90\070\uff90\071\uff90\072\uff90\073\uff90\074\uff90" + "\075\uff90\001\002\000\044\007\uff91\010\uff91\014\uff91\025" + "\015\026\uff91\027\uff91\033\uff91\056\uff91\060\uff91\062\uff91" + "\064\uff91\070\uff91\071\uff91\072\uff91\073\uff91\074\uff91\075" + "\uff91\001\002\000\004\020\uffa7\001\002\000\034\007\055" + "\010\033\014\044\027\061\033\035\056\032\060\031\070" + "\042\071\034\072\050\073\037\074\045\075\036\001\002" + "\000\114\002\uffd2\004\uffd2\005\uffd2\011\uffd2\014\uffd2\015" + "\uffd2\017\uffd2\021\uffd2\022\uffd2\023\uffd2\024\uffd2\026\uffd2" + "\030\uffd2\031\uffd2\033\uffd2\036\uffd2\037\uffd2\040\uffd2\041" + "\uffd2\043\uffd2\046\uffd2\047\uffd2\050\uffd2\051\uffd2\052\uffd2" + "\053\uffd2\054\uffd2\055\uffd2\057\uffd2\060\233\061\uffd2\062" + "\uffd2\063\uffd2\064\uffd2\065\uffd2\066\uffd2\067\uffd2\001\002" + "\000\112\002\uffc8\004\uffc8\005\uffc8\011\uffc8\014\uffc8\015" + "\uffc8\017\uffc8\021\uffc8\022\uffc8\023\uffc8\024\uffc8\026\uffc8" + "\030\uffc8\031\uffc8\033\uffc8\036\uffc8\037\uffc8\040\uffc8\041" + "\uffc8\043\uffc8\046\uffc8\047\uffc8\050\uffc8\051\uffc8\052\uffc8" + "\053\uffc8\054\uffc8\055\uffc8\057\uffc8\061\uffc8\062\uffc8\063" + "\uffc8\064\uffc8\065\uffc8\066\uffc8\067\uffc8\001\002\000\122" + "\002\ufff9\004\ufff9\005\ufff9\011\ufff9\014\ufff9\015\ufff9\017" + "\ufff9\021\ufff9\022\ufff9\023\ufff9\024\ufff9\026\ufff9\030\ufff9" + "\031\ufff9\033\ufff9\036\ufff9\037\ufff9\040\ufff9\041\ufff9\042" + "\ufff9\043\ufff9\046\ufff9\047\ufff9\050\ufff9\051\ufff9\052\ufff9" + "\053\ufff9\054\ufff9\055\ufff9\057\ufff9\060\ufff9\061\ufff9\062" + "\ufff9\063\ufff9\064\ufff9\065\ufff9\066\ufff9\067\ufff9\073\ufff9" + "\074\ufff9\001\002\000\042\007\055\010\033\014\044\026" + "\026\027\061\033\035\056\032\060\031\062\053\064\022" + "\070\042\071\034\072\050\073\037\074\045\075\036\001" + "\002\000\122\002\ufffc\004\ufffc\005\ufffc\011\ufffc\014\ufffc" + "\015\ufffc\017\ufffc\021\ufffc\022\ufffc\023\ufffc\024\ufffc\026" + "\ufffc\030\ufffc\031\ufffc\033\ufffc\036\ufffc\037\ufffc\040\ufffc" + "\041\ufffc\042\ufffc\043\ufffc\046\ufffc\047\ufffc\050\ufffc\051" + "\ufffc\052\ufffc\053\ufffc\054\ufffc\055\ufffc\057\ufffc\060\ufffc" + "\061\ufffc\062\ufffc\063\ufffc\064\ufffc\065\ufffc\066\ufffc\067" + "\ufffc\073\ufffc\074\ufffc\001\002\000\116\002\ufff4\004\ufff4" + "\005\ufff4\011\ufff4\014\ufff4\015\ufff4\017\ufff4\021\ufff4\022" + "\ufff4\023\ufff4\024\ufff4\026\ufff4\030\ufff4\031\ufff4\033\ufff4" + "\036\ufff4\037\ufff4\040\ufff4\041\ufff4\042\ufff4\043\ufff4\046" + "\ufff4\047\ufff4\050\ufff4\051\ufff4\052\ufff4\053\ufff4\054\ufff4" + "\055\ufff4\057\ufff4\060\ufff4\061\ufff4\062\ufff4\063\ufff4\064" + "\ufff4\065\ufff4\066\ufff4\067\ufff4\001\002\000\044\007\055" + "\010\033\014\044\026\026\027\061\033\035\050\uffb6\056" + "\032\060\031\062\053\064\022\070\042\071\034\072\050" + "\073\037\074\045\075\036\001\002\000\046\007\055\010" + "\033\014\044\026\026\027\061\033\035\050\uffb6\056\032" + "\060\031\062\053\064\022\065\uffb5\070\042\071\034\072" + "\050\073\037\074\045\075\036\001\002\000\004\060\221" + "\001\002\000\116\002\uffff\004\uffff\005\uffff\011\uffff\014" + "\uffff\015\uffff\017\uffff\021\uffff\022\uffff\023\uffff\024\uffff" + "\026\uffff\030\uffff\031\uffff\033\uffff\036\uffff\037\uffff\040" + "\uffff\041\uffff\042\uffff\043\uffff\046\uffff\047\uffff\050\uffff" + "\051\uffff\052\uffff\053\uffff\054\uffff\055\uffff\057\uffff\060" + "\uffff\061\uffff\062\uffff\063\uffff\064\uffff\065\uffff\066\uffff" + "\067\uffff\001\002\000\116\002\ufff2\004\ufff2\005\ufff2\011" + "\ufff2\014\ufff2\015\ufff2\017\ufff2\021\ufff2\022\ufff2\023\ufff2" + "\024\ufff2\026\ufff2\030\ufff2\031\ufff2\033\ufff2\036\ufff2\037" + "\ufff2\040\ufff2\041\ufff2\042\ufff2\043\ufff2\046\ufff2\047\ufff2" + "\050\ufff2\051\ufff2\052\ufff2\053\ufff2\054\ufff2\055\ufff2\057" + "\ufff2\060\ufff2\061\ufff2\062\ufff2\063\ufff2\064\ufff2\065\ufff2" + "\066\ufff2\067\ufff2\001\002\000\112\002\uffd4\004\uffd4\005" + "\uffd4\011\uffd4\014\uffd4\015\uffd4\017\uffd4\021\uffd4\022\uffd4" + "\023\uffd4\024\uffd4\026\uffd4\030\uffd4\031\uffd4\033\uffd4\036" + "\uffd4\037\uffd4\040\uffd4\041\uffd4\043\uffd4\046\uffd4\047\uffd4" + "\050\uffd4\051\uffd4\052\uffd4\053\uffd4\054\uffd4\055\uffd4\057" + "\uffd4\061\uffd4\062\uffd4\063\uffd4\064\uffd4\065\uffd4\066\uffd4" + "\067\uffd4\001\002\000\122\002\ufff8\004\ufff8\005\ufff8\011" + "\ufff8\014\ufff8\015\ufff8\017\ufff8\021\ufff8\022\ufff8\023\ufff8" + "\024\ufff8\026\ufff8\030\ufff8\031\ufff8\033\ufff8\036\ufff8\037" + "\ufff8\040\ufff8\041\ufff8\042\ufff8\043\ufff8\046\ufff8\047\ufff8" + "\050\ufff8\051\ufff8\052\ufff8\053\ufff8\054\ufff8\055\ufff8\057" + "\ufff8\060\ufff8\061\ufff8\062\ufff8\063\ufff8\064\ufff8\065\ufff8" + "\066\ufff8\067\ufff8\073\ufff8\074\ufff8\001\002\000\012\014" + "\170\030\uff8f\033\uff85\047\077\001\002\000\040\002\uffb8" + "\005\uffb8\011\uffb8\014\uffb8\024\uffb8\030\uffb8\031\101\033" + "\uffb8\036\uffb8\037\uffb8\043\102\047\uffb8\050\uffb8\065\uffb8" + "\066\uffb8\001\002\000\112\002\uffd3\004\uffd3\005\uffd3\011" + "\uffd3\014\uffd3\015\uffd3\017\uffd3\021\uffd3\022\uffd3\023\uffd3" + "\024\uffd3\026\uffd3\030\uffd3\031\uffd3\033\uffd3\036\uffd3\037" + "\uffd3\040\uffd3\041\uffd3\043\uffd3\046\uffd3\047\uffd3\050\uffd3" + "\051\uffd3\052\uffd3\053\uffd3\054\uffd3\055\uffd3\057\uffd3\061" + "\uffd3\062\uffd3\063\uffd3\064\uffd3\065\uffd3\066\uffd3\067\uffd3" + "\001\002\000\110\002\uffda\004\uffda\005\uffda\011\uffda\014" + "\uffda\015\uffda\017\uffda\021\uffda\022\uffda\023\uffda\024\uffda" + "\026\uffda\030\uffda\031\uffda\033\uffda\036\uffda\037\uffda\040" + "\uffda\041\uffda\043\uffda\046\uffda\047\uffda\050\uffda\051\uffda" + "\053\uffda\054\uffda\055\uffda\057\uffda\061\uffda\062\uffda\063" + "\uffda\064\uffda\065\uffda\066\uffda\067\uffda\001\002\000\116" + "\002\ufff3\004\ufff3\005\ufff3\011\ufff3\014\ufff3\015\ufff3\017" + "\ufff3\021\ufff3\022\ufff3\023\ufff3\024\ufff3\026\ufff3\030\ufff3" + "\031\ufff3\033\ufff3\036\ufff3\037\ufff3\040\ufff3\041\ufff3\042" + "\ufff3\043\ufff3\046\ufff3\047\ufff3\050\ufff3\051\ufff3\052\ufff3" + "\053\ufff3\054\ufff3\055\ufff3\057\ufff3\060\ufff3\061\ufff3\062" + "\ufff3\063\ufff3\064\ufff3\065\ufff3\066\ufff3\067\ufff3\001\002" + "\000\122\002\ufff7\004\ufff7\005\ufff7\011\ufff7\014\ufff7\015" + "\ufff7\017\ufff7\021\ufff7\022\ufff7\023\ufff7\024\ufff7\026\ufff7" + "\030\ufff7\031\ufff7\033\ufff7\036\ufff7\037\ufff7\040\ufff7\041" + "\ufff7\042\ufff7\043\ufff7\046\ufff7\047\ufff7\050\ufff7\051\ufff7" + "\052\ufff7\053\ufff7\054\ufff7\055\ufff7\057\ufff7\060\ufff7\061" + "\ufff7\062\ufff7\063\ufff7\064\ufff7\065\ufff7\066\ufff7\067\ufff7" + "\073\ufff7\074\ufff7\001\002\000\110\002\uffde\004\uffde\005" + "\uffde\011\uffde\014\uffde\015\uffde\017\uffde\021\uffde\022\uffde" + "\023\uffde\024\uffde\026\uffde\030\uffde\031\uffde\033\uffde\036" + "\uffde\037\uffde\040\uffde\041\uffde\043\uffde\046\116\047\uffde" + "\050\uffde\051\uffde\053\uffde\054\uffde\055\uffde\057\uffde\061" + "\uffde\062\uffde\063\uffde\064\uffde\065\uffde\066\uffde\067\117" + "\001\002\000\122\002\ufffd\004\ufffd\005\ufffd\011\ufffd\014" + "\ufffd\015\ufffd\017\ufffd\021\ufffd\022\ufffd\023\ufffd\024\ufffd" + "\026\ufffd\030\ufffd\031\ufffd\033\ufffd\036\ufffd\037\ufffd\040" + "\ufffd\041\ufffd\042\ufffd\043\ufffd\046\ufffd\047\ufffd\050\ufffd" + "\051\ufffd\052\ufffd\053\ufffd\054\ufffd\055\ufffd\057\ufffd\060" + "\ufffd\061\ufffd\062\ufffd\063\ufffd\064\ufffd\065\ufffd\066\ufffd" + "\067\ufffd\073\037\074\045\001\002\000\116\002\000\004" + "\000\005\000\011\000\014\000\015\000\017\000\021\000" + "\022\000\023\000\024\000\026\000\030\000\031\000\033" + "\000\036\000\037\000\040\000\041\000\042\000\043\000" + "\046\000\047\000\050\000\051\000\052\000\053\000\054" + "\000\055\000\057\000\060\000\061\000\062\000\063\000" + "\064\000\065\000\066\000\067\000\001\002\000\052\002" + "\uffee\004\104\005\uffee\011\uffee\014\uffee\015\uffee\017\uffee" + "\024\uffee\030\uffee\031\uffee\033\uffee\036\uffee\037\uffee\040" + "\uffee\041\uffee\043\uffee\047\uffee\050\uffee\065\uffee\066\uffee" + "\001\002\000\052\002\uffeb\004\uffeb\005\uffeb\011\uffeb\014" + "\uffeb\015\uffeb\017\uffeb\024\uffeb\030\uffeb\031\uffeb\033\uffeb" + "\036\uffeb\037\uffeb\040\uffeb\041\uffeb\043\uffeb\047\uffeb\050" + "\uffeb\065\uffeb\066\uffeb\001\002\000\034\007\055\010\033" + "\014\044\027\061\033\035\056\032\060\031\070\042\071" + "\034\072\050\073\037\074\045\075\036\001\002\000\076" + "\002\uffe9\004\uffe9\005\uffe9\011\uffe9\014\uffe9\015\uffe9\017" + "\uffe9\021\140\022\152\023\150\024\uffe9\026\146\030\uffe9" + "\031\uffe9\033\uffe9\036\uffe9\037\uffe9\040\uffe9\041\uffe9\043" + "\uffe9\047\uffe9\050\uffe9\053\143\054\142\055\145\057\144" + "\061\151\063\147\065\uffe9\066\uffe9\001\002\000\050\007" + "\055\010\033\014\044\015\uffc6\017\uffc6\026\026\027\061" + "\033\035\041\uffc6\056\032\060\031\062\053\064\022\070" + "\042\071\034\072\050\073\037\074\045\075\036\001\002" + "\000\104\002\uffe7\004\uffe7\005\uffe7\011\uffe7\014\uffe7\015" + "\uffe7\017\uffe7\021\uffe7\022\uffe7\023\uffe7\024\uffe7\026\uffe7" + "\030\uffe7\031\uffe7\033\uffe7\036\uffe7\037\uffe7\040\uffe7\041" + "\uffe7\043\uffe7\047\uffe7\050\uffe7\051\113\053\uffe7\054\uffe7" + "\055\uffe7\057\uffe7\061\uffe7\062\114\063\uffe7\064\112\065" + "\uffe7\066\uffe7\001\002\000\112\002\uffd7\004\uffd7\005\uffd7" + "\011\uffd7\014\uffd7\015\uffd7\017\uffd7\021\uffd7\022\uffd7\023" + "\uffd7\024\uffd7\026\uffd7\030\uffd7\031\uffd7\033\uffd7\036\uffd7" + "\037\uffd7\040\uffd7\041\uffd7\043\uffd7\046\uffd7\047\uffd7\050" + "\uffd7\051\uffd7\052\065\053\uffd7\054\uffd7\055\uffd7\057\uffd7" + "\061\uffd7\062\uffd7\063\uffd7\064\uffd7\065\uffd7\066\uffd7\067" + "\uffd7\001\002\000\122\002\ufffa\004\ufffa\005\ufffa\011\ufffa" + "\014\ufffa\015\ufffa\017\ufffa\021\ufffa\022\ufffa\023\ufffa\024" + "\ufffa\026\ufffa\030\ufffa\031\ufffa\033\ufffa\036\ufffa\037\ufffa" + "\040\ufffa\041\ufffa\042\ufffa\043\ufffa\046\ufffa\047\ufffa\050" + "\ufffa\051\ufffa\052\ufffa\053\ufffa\054\ufffa\055\ufffa\057\ufffa" + "\060\ufffa\061\ufffa\062\ufffa\063\ufffa\064\ufffa\065\ufffa\066" + "\ufffa\067\ufffa\073\ufffa\074\ufffa\001\002\000\112\002\uffc9" + "\004\uffc9\005\uffc9\011\uffc9\014\uffc9\015\uffc9\017\uffc9\021" + "\uffc9\022\uffc9\023\uffc9\024\uffc9\026\uffc9\030\uffc9\031\uffc9" + "\033\uffc9\036\uffc9\037\uffc9\040\uffc9\041\uffc9\043\uffc9\046" + "\uffc9\047\uffc9\050\uffc9\051\uffc9\052\uffc9\053\uffc9\054\uffc9" + "\055\uffc9\057\uffc9\061\uffc9\062\uffc9\063\uffc9\064\uffc9\065" + "\uffc9\066\uffc9\067\uffc9\001\002\000\116\002\ufffe\004\ufffe" + "\005\ufffe\011\ufffe\014\ufffe\015\ufffe\017\ufffe\021\ufffe\022" + "\ufffe\023\ufffe\024\ufffe\026\ufffe\030\ufffe\031\ufffe\033\ufffe" + "\036\ufffe\037\ufffe\040\ufffe\041\ufffe\042\ufffe\043\ufffe\046" + "\ufffe\047\ufffe\050\ufffe\051\ufffe\052\ufffe\053\ufffe\054\ufffe" + "\055\ufffe\057\ufffe\060\ufffe\061\ufffe\062\ufffe\063\ufffe\064" + "\ufffe\065\ufffe\066\ufffe\067\ufffe\001\002\000\116\002\ufff6" + "\004\ufff6\005\ufff6\011\ufff6\014\ufff6\015\ufff6\017\ufff6\021" + "\ufff6\022\ufff6\023\ufff6\024\ufff6\026\ufff6\030\ufff6\031\ufff6" + "\033\ufff6\036\ufff6\037\ufff6\040\ufff6\041\ufff6\042\ufff6\043" + "\ufff6\046\ufff6\047\ufff6\050\ufff6\051\ufff6\052\ufff6\053\ufff6" + "\054\ufff6\055\ufff6\057\ufff6\060\ufff6\061\ufff6\062\ufff6\063" + "\ufff6\064\ufff6\065\ufff6\066\ufff6\067\ufff6\001\002\000\116" + "\002\ufff5\004\ufff5\005\ufff5\011\ufff5\014\ufff5\015\ufff5\017" + "\ufff5\021\ufff5\022\ufff5\023\ufff5\024\ufff5\026\ufff5\030\ufff5" + "\031\ufff5\033\ufff5\036\ufff5\037\ufff5\040\ufff5\041\ufff5\042" + "\ufff5\043\ufff5\046\ufff5\047\ufff5\050\ufff5\051\ufff5\052\ufff5" + "\053\ufff5\054\ufff5\055\ufff5\057\ufff5\060\ufff5\061\ufff5\062" + "\ufff5\063\ufff5\064\ufff5\065\ufff5\066\ufff5\067\ufff5\001\002" + "\000\016\014\044\033\035\071\034\072\050\073\037\074" + "\045\001\002\000\004\060\072\001\002\000\114\002\uffd1" + "\004\uffd1\005\uffd1\011\uffd1\014\uffd1\015\uffd1\017\uffd1\021" + "\uffd1\022\uffd1\023\uffd1\024\uffd1\026\uffd1\030\uffd1\031\uffd1" + "\033\uffd1\036\uffd1\037\uffd1\040\uffd1\041\uffd1\043\uffd1\046" + "\uffd1\047\uffd1\050\uffd1\051\uffd1\052\uffd1\053\uffd1\054\uffd1" + "\055\uffd1\057\uffd1\060\ufff6\061\uffd1\062\uffd1\063\uffd1\064" + "\uffd1\065\uffd1\066\uffd1\067\uffd1\001\002\000\114\002\uffd0" + "\004\uffd0\005\uffd0\011\uffd0\014\uffd0\015\uffd0\017\uffd0\021" + "\uffd0\022\uffd0\023\uffd0\024\uffd0\026\uffd0\030\uffd0\031\uffd0" + "\033\uffd0\036\uffd0\037\uffd0\040\uffd0\041\uffd0\043\uffd0\046" + "\uffd0\047\uffd0\050\uffd0\051\uffd0\052\uffd0\053\uffd0\054\uffd0" + "\055\uffd0\057\uffd0\060\ufff5\061\uffd0\062\uffd0\063\uffd0\064" + "\uffd0\065\uffd0\066\uffd0\067\uffd0\001\002\000\114\002\uffcf" + "\004\uffcf\005\uffcf\011\uffcf\014\uffcf\015\uffcf\017\uffcf\021" + "\uffcf\022\uffcf\023\uffcf\024\uffcf\026\uffcf\030\uffcf\031\uffcf" + "\033\uffcf\036\uffcf\037\uffcf\040\uffcf\041\uffcf\043\uffcf\046" + "\uffcf\047\uffcf\050\uffcf\051\uffcf\052\uffcf\053\uffcf\054\uffcf" + "\055\uffcf\057\uffcf\060\ufff4\061\uffcf\062\uffcf\063\uffcf\064" + "\uffcf\065\uffcf\066\uffcf\067\uffcf\001\002\000\046\007\055" + "\010\033\014\044\026\026\027\061\033\035\050\uffb6\056" + "\032\060\031\062\053\064\022\066\uffb5\070\042\071\034" + "\072\050\073\037\074\045\075\036\001\002\000\004\066" + "\111\001\002\000\004\050\107\001\002\000\006\065\uffb4" + "\066\uffb4\001\002\000\012\047\077\050\uffb7\065\uffb3\066" + "\uffb3\001\002\000\042\007\055\010\033\014\044\026\026" + "\027\061\033\035\056\032\060\031\062\053\064\022\070" + "\042\071\034\072\050\073\037\074\045\075\036\001\002" + "\000\040\002\uffb9\005\uffb9\011\uffb9\014\uffb9\024\uffb9\030" + "\uffb9\031\101\033\uffb9\036\uffb9\037\uffb9\043\102\047\uffb9" + "\050\uffb9\065\uffb9\066\uffb9\001\002\000\042\007\055\010" + "\033\014\044\026\026\027\061\033\035\056\032\060\031" + "\062\053\064\022\070\042\071\034\072\050\073\037\074" + "\045\075\036\001\002\000\042\007\055\010\033\014\044" + "\026\026\027\061\033\035\056\032\060\031\062\053\064" + "\022\070\042\071\034\072\050\073\037\074\045\075\036" + "\001\002\000\052\002\uffec\004\104\005\uffec\011\uffec\014" + "\uffec\015\uffec\017\uffec\024\uffec\030\uffec\031\uffec\033\uffec" + "\036\uffec\037\uffec\040\uffec\041\uffec\043\uffec\047\uffec\050" + "\uffec\065\uffec\066\uffec\001\002\000\042\007\055\010\033" + "\014\044\026\026\027\061\033\035\056\032\060\031\062" + "\053\064\022\070\042\071\034\072\050\073\037\074\045" + "\075\036\001\002\000\052\002\uffea\004\uffea\005\uffea\011" + "\uffea\014\uffea\015\uffea\017\uffea\024\uffea\030\uffea\031\uffea" + "\033\uffea\036\uffea\037\uffea\040\uffea\041\uffea\043\uffea\047" + "\uffea\050\uffea\065\uffea\066\uffea\001\002\000\052\002\uffed" + "\004\104\005\uffed\011\uffed\014\uffed\015\uffed\017\uffed\024" + "\uffed\030\uffed\031\uffed\033\uffed\036\uffed\037\uffed\040\uffed" + "\041\uffed\043\uffed\047\uffed\050\uffed\065\uffed\066\uffed\001" + "\002\000\044\007\055\010\033\014\044\026\026\027\061" + "\033\035\050\uffb6\056\032\060\031\062\053\064\022\070" + "\042\071\034\072\050\073\037\074\045\075\036\001\002" + "\000\006\065\uffb2\066\uffb2\001\002\000\112\002\uffce\004" + "\uffce\005\uffce\011\uffce\014\uffce\015\uffce\017\uffce\021\uffce" + "\022\uffce\023\uffce\024\uffce\026\uffce\030\uffce\031\uffce\033" + "\uffce\036\uffce\037\uffce\040\uffce\041\uffce\043\uffce\046\uffce" + "\047\uffce\050\uffce\051\uffce\052\uffce\053\uffce\054\uffce\055" + "\uffce\057\uffce\061\uffce\062\uffce\063\uffce\064\uffce\065\uffce" + "\066\uffce\067\uffce\001\002\000\040\007\055\010\033\014" + "\044\027\061\033\035\056\032\060\031\062\053\064\022" + "\070\042\071\034\072\050\073\037\074\045\075\036\001" + "\002\000\040\007\055\010\033\014\044\027\061\033\035" + "\056\032\060\031\062\053\064\022\070\042\071\034\072" + "\050\073\037\074\045\075\036\001\002\000\040\007\055" + "\010\033\014\044\027\061\033\035\056\032\060\031\062" + "\053\064\022\070\042\071\034\072\050\073\037\074\045" + "\075\036\001\002\000\110\002\uffdc\004\uffdc\005\uffdc\011" + "\uffdc\014\uffdc\015\uffdc\017\uffdc\021\uffdc\022\uffdc\023\uffdc" + "\024\uffdc\026\uffdc\030\uffdc\031\uffdc\033\uffdc\036\uffdc\037" + "\uffdc\040\uffdc\041\uffdc\043\uffdc\046\116\047\uffdc\050\uffdc" + "\051\uffdc\053\uffdc\054\uffdc\055\uffdc\057\uffdc\061\uffdc\062" + "\uffdc\063\uffdc\064\uffdc\065\uffdc\066\uffdc\067\117\001\002" + "\000\040\007\055\010\033\014\044\027\061\033\035\056" + "\032\060\031\062\053\064\022\070\042\071\034\072\050" + "\073\037\074\045\075\036\001\002\000\040\007\055\010" + "\033\014\044\027\061\033\035\056\032\060\031\062\053" + "\064\022\070\042\071\034\072\050\073\037\074\045\075" + "\036\001\002\000\110\002\uffd8\004\uffd8\005\uffd8\011\uffd8" + "\014\uffd8\015\uffd8\017\uffd8\021\uffd8\022\uffd8\023\uffd8\024" + "\uffd8\026\uffd8\030\uffd8\031\uffd8\033\uffd8\036\uffd8\037\uffd8" + "\040\uffd8\041\uffd8\043\uffd8\046\uffd8\047\uffd8\050\uffd8\051" + "\uffd8\053\uffd8\054\uffd8\055\uffd8\057\uffd8\061\uffd8\062\uffd8" + "\063\uffd8\064\uffd8\065\uffd8\066\uffd8\067\uffd8\001\002\000" + "\110\002\uffd9\004\uffd9\005\uffd9\011\uffd9\014\uffd9\015\uffd9" + "\017\uffd9\021\uffd9\022\uffd9\023\uffd9\024\uffd9\026\uffd9\030" + "\uffd9\031\uffd9\033\uffd9\036\uffd9\037\uffd9\040\uffd9\041\uffd9" + "\043\uffd9\046\uffd9\047\uffd9\050\uffd9\051\uffd9\053\uffd9\054" + "\uffd9\055\uffd9\057\uffd9\061\uffd9\062\uffd9\063\uffd9\064\uffd9" + "\065\uffd9\066\uffd9\067\uffd9\001\002\000\110\002\uffdb\004" + "\uffdb\005\uffdb\011\uffdb\014\uffdb\015\uffdb\017\uffdb\021\uffdb" + "\022\uffdb\023\uffdb\024\uffdb\026\uffdb\030\uffdb\031\uffdb\033" + "\uffdb\036\uffdb\037\uffdb\040\uffdb\041\uffdb\043\uffdb\046\116" + "\047\uffdb\050\uffdb\051\uffdb\053\uffdb\054\uffdb\055\uffdb\057" + "\uffdb\061\uffdb\062\uffdb\063\uffdb\064\uffdb\065\uffdb\066\uffdb" + "\067\117\001\002\000\110\002\uffdd\004\uffdd\005\uffdd\011" + "\uffdd\014\uffdd\015\uffdd\017\uffdd\021\uffdd\022\uffdd\023\uffdd" + "\024\uffdd\026\uffdd\030\uffdd\031\uffdd\033\uffdd\036\uffdd\037" + "\uffdd\040\uffdd\041\uffdd\043\uffdd\046\116\047\uffdd\050\uffdd" + "\051\uffdd\053\uffdd\054\uffdd\055\uffdd\057\uffdd\061\uffdd\062" + "\uffdd\063\uffdd\064\uffdd\065\uffdd\066\uffdd\067\117\001\002" + "\000\014\015\uffc5\017\uffc5\031\101\041\uffc5\043\102\001" + "\002\000\010\015\uffc4\017\uffc4\041\uffc4\001\002\000\010" + "\015\130\017\uffc1\041\131\001\002\000\004\017\137\001" + "\002\000\042\007\055\010\033\014\044\026\026\027\061" + "\033\035\056\032\060\031\062\053\064\022\070\042\071" + "\034\072\050\073\037\074\045\075\036\001\002\000\042" + "\007\055\010\033\014\044\026\026\027\061\033\035\056" + "\032\060\031\062\053\064\022\070\042\071\034\072\050" + "\073\037\074\045\075\036\001\002\000\010\015\uffc3\017" + "\uffc3\041\uffc3\001\002\000\010\031\101\040\134\043\102" + "\001\002\000\042\007\055\010\033\014\044\026\026\027" + "\061\033\035\056\032\060\031\062\053\064\022\070\042" + "\071\034\072\050\073\037\074\045\075\036\001\002\000" + "\014\015\uffc2\017\uffc2\031\101\041\uffc2\043\102\001\002" + "\000\010\017\uffc0\031\101\043\102\001\002\000\112\002" + "\uffc7\004\uffc7\005\uffc7\011\uffc7\014\uffc7\015\uffc7\017\uffc7" + "\021\uffc7\022\uffc7\023\uffc7\024\uffc7\026\uffc7\030\uffc7\031" + "\uffc7\033\uffc7\036\uffc7\037\uffc7\040\uffc7\041\uffc7\043\uffc7" + "\046\uffc7\047\uffc7\050\uffc7\051\uffc7\052\uffc7\053\uffc7\054" + "\uffc7\055\uffc7\057\uffc7\061\uffc7\062\uffc7\063\uffc7\064\uffc7" + "\065\uffc7\066\uffc7\067\uffc7\001\002\000\040\007\055\010" + "\033\014\044\027\061\033\035\056\032\060\031\062\053" + "\064\022\070\042\071\034\072\050\073\037\074\045\075" + "\036\001\002\000\040\007\055\010\033\014\044\027\061" + "\033\035\056\032\060\031\062\053\064\022\070\042\071" + "\034\072\050\073\037\074\045\075\036\001\002\000\040" + "\007\uffba\010\uffba\014\uffba\027\uffba\033\uffba\056\uffba\060" + "\uffba\062\uffba\064\uffba\070\uffba\071\uffba\072\uffba\073\uffba" + "\074\uffba\075\uffba\001\002\000\040\007\uffbf\010\uffbf\014" + "\uffbf\027\uffbf\033\uffbf\056\uffbf\060\uffbf\062\uffbf\064\uffbf" + "\070\uffbf\071\uffbf\072\uffbf\073\uffbf\074\uffbf\075\uffbf\001" + "\002\000\040\007\uffbb\010\uffbb\014\uffbb\027\uffbb\033\uffbb" + "\056\uffbb\060\uffbb\062\uffbb\064\uffbb\070\uffbb\071\uffbb\072" + "\uffbb\073\uffbb\074\uffbb\075\uffbb\001\002\000\040\007\uffbc" + "\010\uffbc\014\uffbc\027\uffbc\033\uffbc\056\uffbc\060\uffbc\062" + "\uffbc\064\uffbc\070\uffbc\071\uffbc\072\uffbc\073\uffbc\074\uffbc" + "\075\uffbc\001\002\000\006\021\157\023\160\001\002\000" + "\040\007\uffbe\010\uffbe\014\uffbe\027\uffbe\033\uffbe\056\uffbe" + "\060\uffbe\062\uffbe\064\uffbe\070\uffbe\071\uffbe\072\uffbe\073" + "\uffbe\074\uffbe\075\uffbe\001\002\000\040\007\055\010\033" + "\014\044\027\061\033\035\056\032\060\031\062\053\064" + "\022\070\042\071\034\072\050\073\037\074\045\075\036" + "\001\002\000\040\007\uffbd\010\uffbd\014\uffbd\027\uffbd\033" + "\uffbd\056\uffbd\060\uffbd\062\uffbd\064\uffbd\070\uffbd\071\uffbd" + "\072\uffbd\073\uffbd\074\uffbd\075\uffbd\001\002\000\042\007" + "\055\010\033\014\044\016\155\027\154\033\035\056\032" + "\060\031\062\053\064\022\070\042\071\034\072\050\073" + "\037\074\045\075\036\001\002\000\104\002\uffe4\004\uffe4" + "\005\uffe4\011\uffe4\014\uffe4\015\uffe4\017\uffe4\021\uffe4\022" + "\uffe4\023\uffe4\024\uffe4\026\uffe4\030\uffe4\031\uffe4\033\uffe4" + "\036\uffe4\037\uffe4\040\uffe4\041\uffe4\043\uffe4\047\uffe4\050" + "\uffe4\051\113\053\uffe4\054\uffe4\055\uffe4\057\uffe4\061\uffe4" + "\062\114\063\uffe4\064\112\065\uffe4\066\uffe4\001\002\000" + "\112\002\uffe5\004\uffe5\005\uffe5\011\uffe5\014\uffe5\015\uffe5" + "\017\uffe5\021\uffe5\022\uffe5\023\uffe5\024\uffe5\026\uffe5\030" + "\uffe5\031\uffe5\033\uffe5\036\uffe5\037\uffe5\040\uffe5\041\uffe5" + "\043\uffe5\046\uffc9\047\uffe5\050\uffe5\051\uffc9\052\uffc9\053" + "\uffe5\054\uffe5\055\uffe5\057\uffe5\061\uffe5\062\uffc9\063\uffe5" + "\064\uffc9\065\uffe5\066\uffe5\067\uffc9\001\002\000\076\002" + "\uffe3\004\uffe3\005\uffe3\011\uffe3\014\uffe3\015\uffe3\017\uffe3" + "\021\uffe3\022\uffe3\023\uffe3\024\uffe3\026\uffe3\030\uffe3\031" + "\uffe3\033\uffe3\036\uffe3\037\uffe3\040\uffe3\041\uffe3\043\uffe3" + "\047\uffe3\050\uffe3\053\uffe3\054\uffe3\055\uffe3\057\uffe3\061" + "\uffe3\063\uffe3\065\uffe3\066\uffe3\001\002\000\104\002\uffe2" + "\004\uffe2\005\uffe2\011\uffe2\014\uffe2\015\uffe2\017\uffe2\021" + "\uffe2\022\uffe2\023\uffe2\024\uffe2\026\uffe2\030\uffe2\031\uffe2" + "\033\uffe2\036\uffe2\037\uffe2\040\uffe2\041\uffe2\043\uffe2\047" + "\uffe2\050\uffe2\051\113\053\uffe2\054\uffe2\055\uffe2\057\uffe2" + "\061\uffe2\062\114\063\uffe2\064\112\065\uffe2\066\uffe2\001" + "\002\000\040\007\055\010\033\014\044\027\061\033\035" + "\056\032\060\031\062\053\064\022\070\042\071\034\072" + "\050\073\037\074\045\075\036\001\002\000\040\007\055" + "\010\033\014\044\027\061\033\035\056\032\060\031\062" + "\053\064\022\070\042\071\034\072\050\073\037\074\045" + "\075\036\001\002\000\104\002\uffe1\004\uffe1\005\uffe1\011" + "\uffe1\014\uffe1\015\uffe1\017\uffe1\021\uffe1\022\uffe1\023\uffe1" + "\024\uffe1\026\uffe1\030\uffe1\031\uffe1\033\uffe1\036\uffe1\037" + "\uffe1\040\uffe1\041\uffe1\043\uffe1\047\uffe1\050\uffe1\051\113" + "\053\uffe1\054\uffe1\055\uffe1\057\uffe1\061\uffe1\062\114\063" + "\uffe1\064\112\065\uffe1\066\uffe1\001\002\000\104\002\uffdf" + "\004\uffdf\005\uffdf\011\uffdf\014\uffdf\015\uffdf\017\uffdf\021" + "\uffdf\022\uffdf\023\uffdf\024\uffdf\026\uffdf\030\uffdf\031\uffdf" + "\033\uffdf\036\uffdf\037\uffdf\040\uffdf\041\uffdf\043\uffdf\047" + "\uffdf\050\uffdf\051\113\053\uffdf\054\uffdf\055\uffdf\057\uffdf" + "\061\uffdf\062\114\063\uffdf\064\112\065\uffdf\066\uffdf\001" + "\002\000\104\002\uffe6\004\uffe6\005\uffe6\011\uffe6\014\uffe6" + "\015\uffe6\017\uffe6\021\uffe6\022\uffe6\023\uffe6\024\uffe6\026" + "\uffe6\030\uffe6\031\uffe6\033\uffe6\036\uffe6\037\uffe6\040\uffe6" + "\041\uffe6\043\uffe6\047\uffe6\050\uffe6\051\113\053\uffe6\054" + "\uffe6\055\uffe6\057\uffe6\061\uffe6\062\114\063\uffe6\064\112" + "\065\uffe6\066\uffe6\001\002\000\104\002\uffe0\004\uffe0\005" + "\uffe0\011\uffe0\014\uffe0\015\uffe0\017\uffe0\021\uffe0\022\uffe0" + "\023\uffe0\024\uffe0\026\uffe0\030\uffe0\031\uffe0\033\uffe0\036" + "\uffe0\037\uffe0\040\uffe0\041\uffe0\043\uffe0\047\uffe0\050\uffe0" + "\051\113\053\uffe0\054\uffe0\055\uffe0\057\uffe0\061\uffe0\062" + "\114\063\uffe0\064\112\065\uffe0\066\uffe0\001\002\000\112" + "\002\uffd5\004\uffd5\005\uffd5\011\uffd5\014\uffd5\015\uffd5\017" + "\uffd5\021\uffd5\022\uffd5\023\uffd5\024\uffd5\026\uffd5\030\uffd5" + "\031\uffd5\033\uffd5\036\uffd5\037\uffd5\040\uffd5\041\uffd5\043" + "\uffd5\046\uffd5\047\uffd5\050\uffd5\051\uffd5\052\065\053\uffd5" + "\054\uffd5\055\uffd5\057\uffd5\061\uffd5\062\uffd5\063\uffd5\064" + "\uffd5\065\uffd5\066\uffd5\067\uffd5\001\002\000\122\002\ufffb" + "\004\ufffb\005\ufffb\011\ufffb\014\ufffb\015\ufffb\017\ufffb\021" + "\ufffb\022\ufffb\023\ufffb\024\ufffb\026\ufffb\030\ufffb\031\ufffb" + "\033\ufffb\036\ufffb\037\ufffb\040\ufffb\041\ufffb\042\ufffb\043" + "\ufffb\046\ufffb\047\ufffb\050\ufffb\051\ufffb\052\ufffb\053\ufffb" + "\054\ufffb\055\ufffb\057\ufffb\060\ufffb\061\ufffb\062\ufffb\063" + "\ufffb\064\ufffb\065\ufffb\066\ufffb\067\ufffb\073\ufffb\074\ufffb" + "\001\002\000\004\030\uff8e\001\002\000\004\033\uff84\001" + "\002\000\004\030\204\001\002\000\004\033\173\001\002" + "\000\016\014\044\033\035\071\034\072\050\073\037\074" + "\045\001\002\000\010\030\uff81\050\uff81\052\202\001\002" + "\000\024\002\ufff1\005\ufff1\011\ufff1\030\ufff1\033\ufff1\042" + "\ufff1\050\ufff1\052\ufff1\066\ufff1\001\002\000\006\030\uff83" + "\050\200\001\002\000\004\030\uff86\001\002\000\016\014" + "\044\033\035\071\034\072\050\073\037\074\045\001\002" + "\000\004\030\uff82\001\002\000\016\014\044\033\035\071" + "\034\072\050\073\037\074\045\001\002\000\024\002\ufff0" + "\005\ufff0\011\ufff0\030\ufff0\033\ufff0\042\ufff0\050\ufff0\052" + "\ufff0\066\ufff0\001\002\000\020\006\207\012\206\013\213" + "\032\214\034\215\035\205\070\210\001\002\000\006\020" + "\uff8a\050\uff8a\001\002\000\006\020\uff89\050\uff89\001\002" + "\000\004\060\216\001\002\000\006\020\uff88\050\uff88\001" + "\002\000\006\020\uff93\050\uff93\001\002\000\006\020\uff92" + "\050\uff92\001\002\000\006\020\uff8d\050\uff8d\001\002\000" + "\006\020\uff8b\050\uff8b\001\002\000\006\020\uff8c\050\uff8c" + "\001\002\000\004\070\217\001\002\000\004\066\220\001" + "\002\000\006\020\uff87\050\uff87\001\002\000\042\007\055" + "\010\033\014\044\026\026\027\061\033\035\056\032\060" + "\031\062\053\064\022\070\042\071\034\072\050\073\037" + "\074\045\075\036\001\002\000\006\005\223\047\077\001" + "\002\000\016\014\044\033\035\071\034\072\050\073\037" + "\074\045\001\002\000\004\066\225\001\002\000\112\002" + "\uffcc\004\uffcc\005\uffcc\011\uffcc\014\uffcc\015\uffcc\017\uffcc" + "\021\uffcc\022\uffcc\023\uffcc\024\uffcc\026\uffcc\030\uffcc\031" + "\uffcc\033\uffcc\036\uffcc\037\uffcc\040\uffcc\041\uffcc\043\uffcc" + "\046\uffcc\047\uffcc\050\uffcc\051\uffcc\052\uffcc\053\uffcc\054" + "\uffcc\055\uffcc\057\uffcc\061\uffcc\062\uffcc\063\uffcc\064\uffcc" + "\065\uffcc\066\uffcc\067\uffcc\001\002\000\004\065\227\001" + "\002\000\112\002\uffca\004\uffca\005\uffca\011\uffca\014\uffca" + "\015\uffca\017\uffca\021\uffca\022\uffca\023\uffca\024\uffca\026" + "\uffca\030\uffca\031\uffca\033\uffca\036\uffca\037\uffca\040\uffca" + "\041\uffca\043\uffca\046\uffca\047\uffca\050\uffca\051\uffca\052" + "\uffca\053\uffca\054\uffca\055\uffca\057\uffca\061\uffca\062\uffca" + "\063\uffca\064\uffca\065\uffca\066\uffca\067\uffca\001\002\000" + "\004\066\231\001\002\000\112\002\uffcb\004\uffcb\005\uffcb" + "\011\uffcb\014\uffcb\015\uffcb\017\uffcb\021\uffcb\022\uffcb\023" + "\uffcb\024\uffcb\026\uffcb\030\uffcb\031\uffcb\033\uffcb\036\uffcb" + "\037\uffcb\040\uffcb\041\uffcb\043\uffcb\046\uffcb\047\uffcb\050" + "\uffcb\051\uffcb\052\uffcb\053\uffcb\054\uffcb\055\uffcb\057\uffcb" + "\061\uffcb\062\uffcb\063\uffcb\064\uffcb\065\uffcb\066\uffcb\067" + "\uffcb\001\002\000\052\002\uffe8\004\uffe8\005\uffe8\011\uffe8" + "\014\uffe8\015\uffe8\017\uffe8\024\uffe8\030\uffe8\031\uffe8\033" + "\uffe8\036\uffe8\037\uffe8\040\uffe8\041\uffe8\043\uffe8\047\uffe8" + "\050\uffe8\065\uffe8\066\uffe8\001\002\000\046\007\055\010" + "\033\014\044\026\026\027\061\033\035\050\uffb6\056\032" + "\060\031\062\053\064\022\066\uffb5\070\042\071\034\072" + "\050\073\037\074\045\075\036\001\002\000\004\066\235" + "\001\002\000\112\002\uffcd\004\uffcd\005\uffcd\011\uffcd\014" + "\uffcd\015\uffcd\017\uffcd\021\uffcd\022\uffcd\023\uffcd\024\uffcd" + "\026\uffcd\030\uffcd\031\uffcd\033\uffcd\036\uffcd\037\uffcd\040" + "\uffcd\041\uffcd\043\uffcd\046\uffcd\047\uffcd\050\uffcd\051\uffcd" + "\052\uffcd\053\uffcd\054\uffcd\055\uffcd\057\uffcd\061\uffcd\062" + "\uffcd\063\uffcd\064\uffcd\065\uffcd\066\uffcd\067\uffcd\001\002" + "\000\112\002\uffd6\004\uffd6\005\uffd6\011\uffd6\014\uffd6\015" + "\uffd6\017\uffd6\021\uffd6\022\uffd6\023\uffd6\024\uffd6\026\uffd6" + "\030\uffd6\031\uffd6\033\uffd6\036\uffd6\037\uffd6\040\uffd6\041" + "\uffd6\043\uffd6\046\uffd6\047\uffd6\050\uffd6\051\uffd6\052\065" + "\053\uffd6\054\uffd6\055\uffd6\057\uffd6\061\uffd6\062\uffd6\063" + "\uffd6\064\uffd6\065\uffd6\066\uffd6\067\uffd6\001\002\000\020" + "\014\044\033\035\060\241\071\034\072\050\073\037\074" + "\045\001\002\000\016\002\uffef\011\uffef\033\uffef\042\uffef" + "\052\202\066\uffef\001\002\000\006\036\uffac\044\005\001" + "\002\000\014\002\uffa6\011\uffa6\033\uffa6\042\245\066\uffa6" + "\001\002\000\014\002\uffaf\011\uffaf\033\uffaf\042\uffaf\066" + "\uffaf\001\002\000\014\002\uff80\011\uff80\033\uff80\042\uff80" + "\066\uff80\001\002\000\042\007\055\010\033\014\044\026" + "\026\027\061\033\035\056\032\060\031\062\053\064\022" + "\070\042\071\034\072\050\073\037\074\045\075\036\001" + "\002\000\012\002\uffa4\011\252\033\uff7d\066\uffa4\001\002" + "\000\006\002\uffa3\066\uffa3\001\002\000\004\033\253\001" + "\002\000\006\002\uffad\066\uffad\001\002\000\004\033\uff7c" + "\001\002\000\016\014\044\033\035\071\034\072\050\073" + "\037\074\045\001\002\000\012\002\uff79\050\uff79\052\202" + "\066\uff79\001\002\000\006\002\uff7e\066\uff7e\001\002\000" + "\010\002\uff7b\050\257\066\uff7b\001\002\000\016\014\044" + "\033\035\071\034\072\050\073\037\074\045\001\002\000" + "\006\002\uff7a\066\uff7a\001\002\000\012\002\uffa5\011\uffa5" + "\033\uffa5\066\uffa5\001\002\000\014\002\uff7f\011\uff7f\033" + "\uff7f\047\077\066\uff7f\001\002\000\004\066\264\001\002" + "\000\014\002\uffae\011\uffae\033\uffae\042\uffae\066\uffae\001" + "\002\000\010\002\uffb0\031\101\043\102\001\002\000\004" + "\002\001\001\002\000\004\036\uffab\001\002\000\010\024" + "\uffa0\036\uffa0\037\uffa0\001\002\000\010\024\274\036\uffa2" + "\037\272\001\002\000\016\014\044\033\035\071\034\072" + "\050\073\037\074\045\001\002\000\010\024\uff9f\036\uff9f" + "\037\uff9f\001\002\000\016\014\044\033\035\071\034\072" + "\050\073\037\074\045\001\002\000\004\005\277\001\002" + "\000\006\005\uff98\052\202\001\002\000\044\007\055\010" + "\033\014\044\026\026\027\061\033\035\056\032\060\031" + "\062\053\064\022\070\042\071\034\072\050\073\037\074" + "\045\075\036\076\301\001\002\000\016\024\uff9c\031\101" + "\036\uff9c\037\uff9c\043\102\050\302\001\002\000\012\024" + "\uff9c\036\uff9c\037\uff9c\050\302\001\002\000\016\014\044" + "\033\035\071\034\072\050\073\037\074\045\001\002\000" + "\010\024\uff9e\036\uff9e\037\uff9e\001\002\000\010\024\uff9b" + "\036\uff9b\037\uff9b\001\002\000\012\024\uff9a\036\uff9a\037" + "\uff9a\050\311\001\002\000\004\053\307\001\002\000\042" + "\007\055\010\033\014\044\026\026\027\061\033\035\056" + "\032\060\031\062\053\064\022\070\042\071\034\072\050" + "\073\037\074\045\075\036\001\002\000\016\024\uff97\031" + "\101\036\uff97\037\uff97\043\102\050\uff97\001\002\000\016" + "\014\044\033\035\071\034\072\050\073\037\074\045\001" + "\002\000\010\024\uff99\036\uff99\037\uff99\001\002\000\010" + "\024\uff9d\036\uff9d\037\uff9d\001\002\000\004\005\316\001" + "\002\000\006\005\uff94\052\202\001\002\000\044\007\055" + "\010\033\014\044\026\026\027\061\033\035\056\032\060" + "\031\062\053\064\022\070\042\071\034\072\050\073\037" + "\074\045\075\036\076\317\001\002\000\010\024\uff96\036" + "\uff96\037\uff96\001\002\000\012\024\uff95\036\uff95\037\uff95" + "\047\077\001\002\000\004\036\uffa1\001\002" }); /** Access to parse-action table. */ public short[][] action_table() {return _action_table;} /** reduce_goto table. */ protected static final short[][] _reduce_table = unpackFromStrings(new String[] { "\000\317\000\010\024\003\026\005\076\007\001\001\000" + "\002\001\001\000\012\025\270\050\267\051\272\071\266" + "\001\001\000\002\001\001\000\046\004\023\011\042\013" + "\045\014\055\015\053\016\051\017\050\020\264\022\056" + "\037\061\040\022\041\027\042\063\043\062\044\026\045" + "\057\046\024\047\046\001\001\000\002\001\001\000\012" + "\003\013\057\012\060\015\061\011\001\001\000\002\001" + "\001\000\050\004\023\007\037\011\042\013\045\014\055" + "\015\053\016\051\017\050\020\040\022\056\037\061\040" + "\022\041\027\042\063\043\062\044\026\045\057\046\024" + "\047\046\001\001\000\002\001\001\000\002\001\001\000" + "\002\001\001\000\002\001\001\000\010\003\013\057\012" + "\060\020\001\001\000\002\001\001\000\030\004\023\022" + "\235\037\061\040\022\041\027\042\063\043\062\044\026" + "\045\057\046\024\047\046\001\001\000\002\001\001\000" + "\002\001\001\000\002\001\001\000\042\004\023\011\042" + "\013\045\014\055\015\053\016\231\022\056\037\061\040" + "\022\041\027\042\063\043\062\044\026\045\057\046\024" + "\047\046\001\001\000\002\001\001\000\002\001\001\000" + "\054\004\023\007\075\010\073\011\042\013\045\014\055" + "\015\053\016\051\017\050\020\040\022\056\037\061\040" + "\022\041\027\042\063\043\062\044\026\045\057\046\024" + "\047\046\067\227\001\001\000\056\004\023\007\075\010" + "\073\011\042\013\045\014\055\015\053\016\051\017\050" + "\020\040\022\056\037\061\040\022\041\027\042\063\043" + "\062\044\026\045\057\046\024\047\046\067\074\070\225" + "\001\001\000\002\001\001\000\002\001\001\000\002\001" + "\001\000\002\001\001\000\002\001\001\000\010\054\171" + "\065\166\066\170\001\001\000\002\001\001\000\002\001" + "\001\000\002\001\001\000\002\001\001\000\002\001\001" + "\000\002\001\001\000\010\044\165\045\057\046\024\001" + "\001\000\002\001\001\000\002\001\001\000\002\001\001" + "\000\030\004\023\022\164\037\061\040\022\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\001\001" + "\000\004\036\140\001\001\000\050\004\023\011\042\013" + "\045\014\055\015\053\016\051\017\050\020\123\021\124" + "\022\056\037\061\040\022\041\027\042\063\043\062\044" + "\026\045\057\046\024\047\046\001\001\000\002\001\001" + "\000\002\001\001\000\002\001\001\000\002\001\001\000" + "\002\001\001\000\002\001\001\000\002\001\001\000\024" + "\037\061\040\065\041\070\042\067\043\066\044\026\045" + "\057\046\024\047\046\001\001\000\002\001\001\000\002" + "\001\001\000\002\001\001\000\002\001\001\000\056\004" + "\023\007\075\010\073\011\042\013\045\014\055\015\053" + "\016\051\017\050\020\040\022\056\037\061\040\022\041" + "\027\042\063\043\062\044\026\045\057\046\024\047\046" + "\067\074\070\072\001\001\000\002\001\001\000\002\001" + "\001\000\002\001\001\000\002\001\001\000\046\004\023" + "\011\042\013\045\014\055\015\053\016\051\017\050\020" + "\077\022\056\037\061\040\022\041\027\042\063\043\062" + "\044\026\045\057\046\024\047\046\001\001\000\002\001" + "\001\000\044\004\023\011\042\013\045\014\055\015\053" + "\016\051\017\105\022\056\037\061\040\022\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\001\001" + "\000\044\004\023\011\042\013\045\014\055\015\053\016" + "\051\017\102\022\056\037\061\040\022\041\027\042\063" + "\043\062\044\026\045\057\046\024\047\046\001\001\000" + "\002\001\001\000\042\004\023\011\042\013\045\014\055" + "\015\053\016\104\022\056\037\061\040\022\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\001\001" + "\000\002\001\001\000\002\001\001\000\054\004\023\007" + "\075\010\073\011\042\013\045\014\055\015\053\016\051" + "\017\050\020\040\022\056\037\061\040\022\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\067\107" + "\001\001\000\002\001\001\000\002\001\001\000\034\004" + "\023\011\042\013\122\022\056\037\061\040\022\041\027" + "\042\063\043\062\044\026\045\057\046\024\047\046\001" + "\001\000\034\004\023\011\042\013\121\022\056\037\061" + "\040\022\041\027\042\063\043\062\044\026\045\057\046" + "\024\047\046\001\001\000\034\004\023\011\042\013\114" + "\022\056\037\061\040\022\041\027\042\063\043\062\044" + "\026\045\057\046\024\047\046\001\001\000\002\001\001" + "\000\032\004\023\011\120\022\056\037\061\040\022\041" + "\027\042\063\043\062\044\026\045\057\046\024\047\046" + "\001\001\000\032\004\023\011\117\022\056\037\061\040" + "\022\041\027\042\063\043\062\044\026\045\057\046\024" + "\047\046\001\001\000\002\001\001\000\002\001\001\000" + "\002\001\001\000\002\001\001\000\002\001\001\000\004" + "\075\125\001\001\000\006\006\126\077\131\001\001\000" + "\002\001\001\000\046\004\023\011\042\013\045\014\055" + "\015\053\016\051\017\050\020\135\022\056\037\061\040" + "\022\041\027\042\063\043\062\044\026\045\057\046\024" + "\047\046\001\001\000\046\004\023\011\042\013\045\014" + "\055\015\053\016\051\017\050\020\132\022\056\037\061" + "\040\022\041\027\042\063\043\062\044\026\045\057\046" + "\024\047\046\001\001\000\002\001\001\000\002\001\001" + "\000\046\004\023\011\042\013\045\014\055\015\053\016" + "\051\017\050\020\134\022\056\037\061\040\022\041\027" + "\042\063\043\062\044\026\045\057\046\024\047\046\001" + "\001\000\002\001\001\000\002\001\001\000\002\001\001" + "\000\036\004\023\011\042\013\045\014\163\022\056\037" + "\061\040\022\041\027\042\063\043\062\044\026\045\057" + "\046\024\047\046\001\001\000\036\004\023\011\042\013" + "\045\014\162\022\056\037\061\040\022\041\027\042\063" + "\043\062\044\026\045\057\046\024\047\046\001\001\000" + "\002\001\001\000\002\001\001\000\002\001\001\000\002" + "\001\001\000\002\001\001\000\002\001\001\000\036\004" + "\023\011\042\013\045\014\155\022\056\037\061\040\022" + "\041\027\042\063\043\062\044\026\045\057\046\024\047" + "\046\001\001\000\002\001\001\000\036\004\023\011\042" + "\013\045\014\152\022\056\037\061\040\022\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\001\001" + "\000\002\001\001\000\002\001\001\000\002\001\001\000" + "\002\001\001\000\036\004\023\011\042\013\045\014\161" + "\022\056\037\061\040\022\041\027\042\063\043\062\044" + "\026\045\057\046\024\047\046\001\001\000\036\004\023" + "\011\042\013\045\014\160\022\056\037\061\040\022\041" + "\027\042\063\043\062\044\026\045\057\046\024\047\046" + "\001\001\000\002\001\001\000\002\001\001\000\002\001" + "\001\000\002\001\001\000\002\001\001\000\002\001\001" + "\000\002\001\001\000\002\001\001\000\002\001\001\000" + "\002\001\001\000\032\030\173\037\061\040\174\041\027" + "\042\063\043\062\044\026\045\057\046\024\047\046\055" + "\175\073\176\001\001\000\002\001\001\000\002\001\001" + "\000\002\001\001\000\002\001\001\000\032\030\173\037" + "\061\040\174\041\027\042\063\043\062\044\026\045\057" + "\046\024\047\046\055\175\073\200\001\001\000\002\001" + "\001\000\024\037\061\040\202\041\027\042\063\043\062" + "\044\026\045\057\046\024\047\046\001\001\000\002\001" + "\001\000\006\035\210\100\211\001\001\000\002\001\001" + "\000\002\001\001\000\002\001\001\000\002\001\001\000" + "\002\001\001\000\002\001\001\000\002\001\001\000\002" + "\001\001\000\002\001\001\000\002\001\001\000\002\001" + "\001\000\002\001\001\000\050\004\023\007\221\011\042" + "\013\045\014\055\015\053\016\051\017\050\020\040\022" + "\056\037\061\040\022\041\027\042\063\043\062\044\026" + "\045\057\046\024\047\046\001\001\000\002\001\001\000" + "\024\037\061\040\223\041\027\042\063\043\062\044\026" + "\045\057\046\024\047\046\001\001\000\002\001\001\000" + "\002\001\001\000\002\001\001\000\002\001\001\000\002" + "\001\001\000\002\001\001\000\002\001\001\000\056\004" + "\023\007\075\010\073\011\042\013\045\014\055\015\053" + "\016\051\017\050\020\040\022\056\037\061\040\022\041" + "\027\042\063\043\062\044\026\045\057\046\024\047\046" + "\067\074\070\233\001\001\000\002\001\001\000\002\001" + "\001\000\002\001\001\000\034\005\241\030\237\031\243" + "\032\242\037\061\040\174\041\027\042\063\043\062\044" + "\026\045\057\046\024\047\046\001\001\000\002\001\001" + "\000\006\024\262\076\007\001\001\000\004\023\245\001" + "\001\000\002\001\001\000\002\001\001\000\052\004\023" + "\007\261\011\042\012\260\013\045\014\055\015\053\016" + "\051\017\050\020\040\022\056\037\061\040\022\041\027" + "\042\063\043\062\044\026\045\057\046\024\047\046\001" + "\001\000\010\053\247\062\246\063\250\001\001\000\002" + "\001\001\000\002\001\001\000\002\001\001\000\002\001" + "\001\000\032\027\255\030\253\037\061\040\174\041\027" + "\042\063\043\062\044\026\045\057\046\024\047\046\074" + "\254\001\001\000\002\001\001\000\002\001\001\000\002" + "\001\001\000\032\027\255\030\253\037\061\040\174\041" + "\027\042\063\043\062\044\026\045\057\046\024\047\046" + "\074\257\001\001\000\002\001\001\000\002\001\001\000" + "\002\001\001\000\002\001\001\000\002\001\001\000\002" + "\001\001\000\002\001\001\000\002\001\001\000\002\001" + "\001\000\012\025\270\050\267\051\272\071\320\001\001" + "\000\030\030\314\034\313\037\061\040\174\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\001\001" + "\000\002\001\001\000\030\030\275\033\274\037\061\040" + "\174\041\027\042\063\043\062\044\026\045\057\046\024" + "\047\046\001\001\000\002\001\001\000\002\001\001\000" + "\046\004\023\011\042\013\045\014\055\015\053\016\051" + "\017\050\020\277\022\056\037\061\040\022\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\001\001" + "\000\004\064\312\001\001\000\004\064\302\001\001\000" + "\030\037\061\040\305\041\027\042\063\043\062\044\026" + "\045\057\046\024\047\046\052\304\072\303\001\001\000" + "\002\001\001\000\002\001\001\000\002\001\001\000\002" + "\001\001\000\046\004\023\011\042\013\045\014\055\015" + "\053\016\051\017\050\020\307\022\056\037\061\040\022" + "\041\027\042\063\043\062\044\026\045\057\046\024\047" + "\046\001\001\000\002\001\001\000\030\037\061\040\305" + "\041\027\042\063\043\062\044\026\045\057\046\024\047" + "\046\052\304\072\311\001\001\000\002\001\001\000\002" + "\001\001\000\002\001\001\000\002\001\001\000\050\004" + "\023\007\317\011\042\013\045\014\055\015\053\016\051" + "\017\050\020\040\022\056\037\061\040\022\041\027\042" + "\063\043\062\044\026\045\057\046\024\047\046\001\001" + "\000\002\001\001\000\002\001\001\000\002\001\001" }); /** Access to reduce_goto table. */ public short[][] reduce_table() {return _reduce_table;} /** Instance of action encapsulation class. */ protected CUP$DefaultMdxParser$actions action_obj; /** Action encapsulation object initializer. */ protected void init_actions() { action_obj = new CUP$DefaultMdxParser$actions(this); } /** Invoke a user supplied parse action. */ public java_cup.runtime.Symbol do_action( int act_num, java_cup.runtime.lr_parser parser, java.util.Stack stack, int top) throws java.lang.Exception { /* call code in generated class */ return action_obj.CUP$DefaultMdxParser$do_action(act_num, parser, stack, top); } /** Indicates start state. */ public int start_state() {return 0;} /** Indicates start production. */ public int start_production() {return 0;} /** EOF Symbol index. */ public int EOF_sym() {return 0;} /** error Symbol index. */ public int error_sym() {return 1;} /** User initialization code. */ public void user_init() throws java.lang.Exception { scanner.init(); } /** Scan to get the next Symbol. */ public java_cup.runtime.Symbol scan() throws java.lang.Exception { return scanner.next_token(); } // Generated from $Id: DefaultMdxParser.cup 482 2012-01-05 23:27:27Z jhyde $ Scanner scanner; private String queryString; private DefaultMdxParserImpl.FunTable funTable; /** * Recursively parses an expression. */ ParseTreeNode recursivelyParseExp(String s) { return new DefaultMdxParser().parseExpression( s, false, funTable); } /** * Parses a string to create a {@link SelectNode}. */ SelectNode parseSelect( String queryString, boolean debug, DefaultMdxParserImpl.FunTable funTable) { Symbol parse_tree = null; this.scanner = new StringScanner(queryString, debug); this.queryString = queryString; this.funTable = funTable; try { if (debug) { parse_tree = debug_parse(); } else { parse_tree = parse(); } return (SelectNode) parse_tree.value; } catch (Exception e) { throw new RuntimeException( "Error while parsing MDX statement '" + queryString + "'", e); } finally { this.scanner = null; this.queryString = null; this.funTable = null; } } /** * Parses a string to create an expression. */ ParseTreeNode parseExpression( String queryString, boolean debug, DefaultMdxParserImpl.FunTable funTable) { Symbol parse_tree = null; this.scanner = new PrefixScanner( debug, new StringScanner(queryString, debug), new int[] {DefaultMdxParserSym._VALUE_EXPRESSION}); this.queryString = queryString; this.funTable = funTable; try { if (debug) { parse_tree = debug_parse(); } else { parse_tree = parse(); } return (ParseTreeNode) parse_tree.value; } catch (Exception e) { throw new RuntimeException( "Syntax error while parsing MDX expression '" + queryString + "'", e); } finally { this.scanner = null; this.queryString = null; this.funTable = null; } } /** * Scanner which returns a list of pre-programmed tokens, then switches * to a parent scanner. */ private static class PrefixScanner extends Scanner { private final Scanner parent; private final int tokens[]; private int i; PrefixScanner(boolean debug, Scanner parent, int[] tokens) { super(debug); this.parent = parent; this.tokens = tokens; } public void init() throws java.io.IOException { i = 0; parent.init(); } public Symbol next_token() throws java.io.IOException { if (i < tokens.length) { return new Symbol(tokens[i++], 0, 0, null); } return parent.next_token(); } ParseRegion createRegion(int left, int right) { return parent.createRegion(left, right); } } /** * Creates a {@link SelectNode} object. * Override this function to make your kind of query. */ protected SelectNode newSelect( ParseRegion region, List withList, List axisList, ParseTreeNode from, ParseTreeNode filter, List cellProps) { final AxisNode filterAxis = filter == null ? null : new AxisNode( filter.getRegion(), false, Axis.FILTER, Collections.emptyList(), filter); // sort axes by ordinal Collections.sort( axisList, new Comparator() { public int compare(AxisNode o1, AxisNode o2) { return o1.getAxis().axisOrdinal() - o2.getAxis().axisOrdinal(); } }); return new SelectNode( region, withList, axisList, from, filterAxis, cellProps); } // Override lr_parser methods for NLS. With this error handling scheme, // all errors are fatal. public void report_fatal_error( String message, Object info) throws java.lang.Exception { done_parsing(); try { report_error(message, info); } catch (Throwable e) { throw new RuntimeException( "MDX parser cannot recover from previous error(s)", e); } } // override lr_parser method public void report_error(String message, Object info) { // "Error: %1" throw new RuntimeException("Error: " + message); } // override lr_parser method public void syntax_error(Symbol cur_token) { String s = cur_token.value.toString(); if (cur_token.left != -1) { final ParseRegion region = scanner.createRegion(cur_token.left, cur_token.right); throw new MdxParseException( region, "Syntax error at " + region + ", token '" + s + "'"); } else { throw new RuntimeException( "Syntax error at token '" + s + "'"); } } public void unrecovered_syntax_error(Symbol cur_token) throws java.lang.Exception { report_fatal_error("Couldn't repair and continue parse", cur_token); } /** * Returns whether the given identifier can possibly the name of an operator * with property syntax. * *

      For example, isFunCall("ORDINAL") * returns true because there is a "<Level>.Ordinal" property.

      */ protected boolean isFunCall(String s) { return funTable.isProperty(s); } } /** Cup generated class to encapsulate user supplied action code.*/ class CUP$DefaultMdxParser$actions { ParseRegion createRegion(final int... ordinals) { assert ordinals.length % 2 == 0; return ParseRegion.sum( new Iterable() { public Iterator iterator() { return new Iterator() { int i = 0; public boolean hasNext() { return i < ordinals.length; } public ParseRegion next() { return parser.scanner.createRegion( ordinals[i++], ordinals[i++]); } public void remove() { throw new UnsupportedOperationException(); } }; } } ); } static List emptyList(List list) { if (list == null) { return Collections.emptyList(); } return list; } private final DefaultMdxParser parser; /** Constructor */ CUP$DefaultMdxParser$actions(DefaultMdxParser parser) { this.parser = parser; } /** Method with the actual generated action code. */ public final java_cup.runtime.Symbol CUP$DefaultMdxParser$do_action( int CUP$DefaultMdxParser$act_num, java_cup.runtime.lr_parser CUP$DefaultMdxParser$parser, java.util.Stack CUP$DefaultMdxParser$stack, int CUP$DefaultMdxParser$top) throws java.lang.Exception { /* Symbol object for return from actions */ java_cup.runtime.Symbol CUP$DefaultMdxParser$result; /* select the action based on the action number */ switch (CUP$DefaultMdxParser$act_num) { /*. . . . . . . . . . . . . . . . . . . .*/ case 136: // cell_property ::= compound_id { IdentifierNode RESULT = null; // Default action for single-symbol production RESULT = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(21/*cell_property*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 135: // cell_property_list ::= cell_property COMMA cell_property_list { List RESULT = null; int pleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int pright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; IdentifierNode p = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int p1left = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int p1right = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List p1 = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; p1.add(0, p); RESULT = p1; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(58/*cell_property_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 134: // cell_property_list ::= cell_property { List RESULT = null; int pleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int pright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierNode p = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new LinkedList(); RESULT.add(p); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(58/*cell_property_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 133: // cell_opt ::= CELL { Object RESULT = null; // Default action for single-symbol production RESULT = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(41/*cell_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 132: // cell_opt ::= { Object RESULT = null; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(41/*cell_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 131: // cell_props ::= cell_opt PROPERTIES cell_property_list { List RESULT = null; int p1left = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int p1right = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List p1 = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = p1; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(48/*cell_props*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 130: // filter_specification ::= expression { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(8/*filter_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 129: // cube_specification ::= cube_name { IdentifierNode RESULT = null; // Default action for single-symbol production RESULT = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(24/*cube_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 128: // property ::= compound_id { Object RESULT = null; // Default action for single-symbol production RESULT = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(43/*property*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 127: // property_list ::= property COMMA property_list { List RESULT = null; int pleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int pright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; Object p = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int plleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int plright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List pl = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; pl.add(0, p); RESULT = pl; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(57/*property_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 126: // property_list ::= property { List RESULT = null; int pleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int pright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object p = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new LinkedList(); RESULT.add(p); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(57/*property_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 125: // dimension_opt ::= DIMENSION { Object RESULT = null; // Default action for single-symbol production RESULT = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(42/*dimension_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 124: // dimension_opt ::= { Object RESULT = null; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(42/*dimension_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 123: // dim_props ::= dimension_opt PROPERTIES property_list { List RESULT = null; int plleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int plright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List pl = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = pl; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(51/*dim_props*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 122: // axis_number ::= AXIS LPAREN NUMBER RPAREN { BigDecimal RESULT = null; int nleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int nright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; BigDecimal n = (BigDecimal)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; RESULT = n; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(62/*axis_number*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 121: // axis_number ::= NUMBER { BigDecimal RESULT = null; // Default action for single-symbol production RESULT = (BigDecimal)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(62/*axis_number*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 120: // axis_name ::= CHAPTERS { Axis.Standard RESULT = null; RESULT = Axis.CHAPTERS; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(27/*axis_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 119: // axis_name ::= SECTIONS { Axis.Standard RESULT = null; RESULT = Axis.SECTIONS; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(27/*axis_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 118: // axis_name ::= PAGES { Axis.Standard RESULT = null; RESULT = Axis.PAGES; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(27/*axis_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 117: // axis_name ::= ROWS { Axis.Standard RESULT = null; RESULT = Axis.ROWS; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(27/*axis_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 116: // axis_name ::= COLUMNS { Axis.Standard RESULT = null; RESULT = Axis.COLUMNS; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(27/*axis_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 115: // dim_props_opt ::= dim_props { List RESULT = null; // Default action for single-symbol production RESULT = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(52/*dim_props_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 114: // dim_props_opt ::= { List RESULT = null; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(52/*dim_props_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 113: // non_empty_opt ::= NON EMPTY { Boolean RESULT = null; RESULT = Boolean.TRUE; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(45/*non_empty_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 112: // non_empty_opt ::= { Boolean RESULT = null; RESULT = Boolean.FALSE; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(45/*non_empty_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 111: // axis_specification ::= non_empty_opt expression dim_props_opt ON axis_number { AxisNode RESULT = null; int bleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left; int bright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).right; Boolean b = (Boolean)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).value; int sleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int sright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; ParseTreeNode s = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int dpleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int dpright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; List dp = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int nleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int nright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; BigDecimal n = (BigDecimal)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; double d = n.doubleValue(); int index = (int)d; // AxisOrdinal values go from -2 to 4 for standard axis, but higher // ordinals are allowed. The negative values represent // special cases, so are ignored. if (index < 0 || index != d) { throw new MdxParseException( createRegion(nleft, nright), "Invalid axis specification. The axis number must be a " + "non-negative integer, but it was " + d + "."); } Axis axis = Axis.Factory.forOrdinal(index); ParseRegion region = createRegion( bleft, bright, sleft, sright, dpleft, dpright, nleft, nright); RESULT = new AxisNode(region, b, axis, emptyList(dp), s); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(1/*axis_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 110: // axis_specification ::= non_empty_opt expression dim_props_opt ON axis_name { AxisNode RESULT = null; int bleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left; int bright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).right; Boolean b = (Boolean)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).value; int sleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int sright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; ParseTreeNode s = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int dpleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int dpright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; List dp = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int aleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int aright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Axis.Standard a = (Axis.Standard)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion( bleft, bright, sleft, sright, dpleft, dpright, aleft, aright); RESULT = new AxisNode(region, b, a, emptyList(dp), s); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(1/*axis_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 109: // set_name ::= compound_id { IdentifierNode RESULT = null; // Default action for single-symbol production RESULT = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(26/*set_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 108: // set_specification ::= SET set_name AS expression { WithSetNode RESULT = null; int setleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int setright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; Object set = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int nleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int nright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; IdentifierNode n = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(setleft, eright); RESULT = new WithSetNode(region, n, e); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(39/*set_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 107: // set_specification ::= SET set_name AS FORMULA_STRING { WithSetNode RESULT = null; int setleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int setright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; Object set = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int nleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int nright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; IdentifierNode n = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int sleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int sright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; String s = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseTreeNode e = parser.recursivelyParseExp(s); ParseRegion region = createRegion(setleft, sright); RESULT = new WithSetNode(region, n, e); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(39/*set_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 106: // member_property_definition ::= identifier EQ value_expression { PropertyValueNode RESULT = null; int idleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int idright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; IdentifierSegment id = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(idleft, eright); RESULT = new PropertyValueNode(region, id.getName(), e); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(40/*member_property_definition*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 105: // member_name ::= compound_id { IdentifierNode RESULT = null; // Default action for single-symbol production RESULT = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(25/*member_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 104: // member_property_def_list ::= member_property_definition COMMA member_property_def_list { List RESULT = null; int hdleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int hdright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; PropertyValueNode hd = (PropertyValueNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int tlleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int tlright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List tl = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = tl; RESULT.add(0, hd); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(56/*member_property_def_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 103: // member_property_def_list ::= member_property_definition { List RESULT = null; int mleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int mright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; PropertyValueNode m = (PropertyValueNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new LinkedList(); RESULT.add(m); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(56/*member_property_def_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 102: // comma_member_property_def_list_opt ::= COMMA member_property_def_list { List RESULT = null; int lleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int lright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List l = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = l; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(50/*comma_member_property_def_list_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 101: // comma_member_property_def_list_opt ::= { List RESULT = null; RESULT = new LinkedList(); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(50/*comma_member_property_def_list_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 100: // member_specification ::= MEMBER member_name AS value_expression comma_member_property_def_list_opt { WithMemberNode RESULT = null; int memberleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left; int memberright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).right; Object member = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).value; int mleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int mright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; IdentifierNode m = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int lleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int lright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List l = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(memberleft, eright); RESULT = new WithMemberNode(region, m, e, l); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(38/*member_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 99: // member_specification ::= MEMBER member_name AS FORMULA_STRING comma_member_property_def_list_opt { WithMemberNode RESULT = null; int memberleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left; int memberright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).right; Object member = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).value; int mleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int mright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; IdentifierNode m = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int sleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int sright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; String s = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int lleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int lright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List l = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseTreeNode e = parser.recursivelyParseExp(s); ParseRegion region = createRegion(memberleft, sright); RESULT = new WithMemberNode(region, m, e, l); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(38/*member_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 98: // single_formula_specification ::= set_specification { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (WithSetNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(19/*single_formula_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 97: // single_formula_specification ::= member_specification { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (WithMemberNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(19/*single_formula_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 96: // formula_specification ::= single_formula_specification formula_specification { List RESULT = null; int hdleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int hdright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; ParseTreeNode hd = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int tlleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int tlright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List tl = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; tl.add(0, hd); RESULT = tl; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(55/*formula_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 95: // formula_specification ::= single_formula_specification { List RESULT = null; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new LinkedList(); RESULT.add(e); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(55/*formula_specification*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 94: // cell_props_opt ::= cell_props { List RESULT = null; // Default action for single-symbol production RESULT = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(49/*cell_props_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 93: // cell_props_opt ::= { List RESULT = null; RESULT = new LinkedList(); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(49/*cell_props_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 92: // where_clause_opt ::= WHERE filter_specification { ParseTreeNode RESULT = null; int sleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int sright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode s = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = s; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(17/*where_clause_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 91: // where_clause_opt ::= { ParseTreeNode RESULT = null; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(17/*where_clause_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 90: // axis_specification_list ::= axis_specification COMMA axis_specification_list { List RESULT = null; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; AxisNode e = (AxisNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int listleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int listright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List list = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; list.add(0, e); RESULT = list; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(46/*axis_specification_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 89: // axis_specification_list ::= axis_specification { List RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; AxisNode i = (AxisNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new LinkedList(); RESULT.add(i); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(46/*axis_specification_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 88: // axis_specification_list_opt ::= axis_specification_list { List RESULT = null; // Default action for single-symbol production RESULT = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(47/*axis_specification_list_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 87: // axis_specification_list_opt ::= { List RESULT = null; RESULT = new LinkedList(); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(47/*axis_specification_list_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 86: // with_formula_specification_opt ::= WITH formula_specification { List RESULT = null; int fleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int fright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List f = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = f; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(60/*with_formula_specification_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 85: // with_formula_specification_opt ::= { List RESULT = null; RESULT = new LinkedList(); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(60/*with_formula_specification_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 84: // select_statement ::= with_formula_specification_opt SELECT axis_specification_list_opt FROM cube_specification_or_select_statement where_clause_opt cell_props_opt { ParseTreeNode RESULT = null; int fleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-6)).left; int fright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-6)).right; List f = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-6)).value; int selectleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).left; int selectright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).right; Object select = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).value; int aleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left; int aright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).right; List a = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).value; int cleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int cright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode c = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int wleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int wright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; ParseTreeNode w = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int cpleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int cpright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List cp = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(selectleft, selectright); RESULT = parser.newSelect(region, f, a, c, w, cp); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(18/*select_statement*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-6)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 83: // cube_specification_or_select_statement ::= LPAREN select_statement RPAREN { ParseTreeNode RESULT = null; int sleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int sright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; ParseTreeNode s = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; RESULT = s; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(3/*cube_specification_or_select_statement*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 82: // cube_specification_or_select_statement ::= cube_specification { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(3/*cube_specification_or_select_statement*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 81: // statement ::= _VALUE_EXPRESSION value_expression { ParseTreeNode RESULT = null; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = (ParseTreeNode) e; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(20/*statement*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 80: // statement ::= select_statement { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(20/*statement*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 79: // exp_list ::= expression_or_empty COMMA exp_list { List RESULT = null; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int listleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int listright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List list = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; list.add(0, e); RESULT = list; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(53/*exp_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 78: // exp_list ::= expression { List RESULT = null; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new LinkedList(); RESULT.add(e); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(53/*exp_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 77: // exp_list_opt ::= exp_list { List RESULT = null; // Default action for single-symbol production RESULT = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(54/*exp_list_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 76: // exp_list_opt ::= { List RESULT = null; RESULT = new LinkedList(); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(54/*exp_list_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 75: // expression_or_empty ::= { ParseTreeNode RESULT = null; final ParseRegion region = createRegion(0, 0); RESULT = new CallNode(region, "", Syntax.Empty); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(6/*expression_or_empty*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 74: // expression_or_empty ::= expression { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(6/*expression_or_empty*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 73: // expression ::= value_expression { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(5/*expression*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 72: // expression ::= expression COLON value_expression { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; // range yields set ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, ":", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(5/*expression*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 71: // comp_op ::= GE { String RESULT = null; RESULT = ">="; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(28/*comp_op*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 70: // comp_op ::= LE { String RESULT = null; RESULT = "<="; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(28/*comp_op*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 69: // comp_op ::= GT { String RESULT = null; RESULT = ">"; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(28/*comp_op*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 68: // comp_op ::= LT { String RESULT = null; RESULT = "<"; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(28/*comp_op*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 67: // comp_op ::= NE { String RESULT = null; RESULT = "<>"; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(28/*comp_op*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 66: // comp_op ::= EQ { String RESULT = null; RESULT = "="; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(28/*comp_op*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 65: // else_clause_opt ::= ELSE value_expression { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = x; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(4/*else_clause_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 64: // else_clause_opt ::= { ParseTreeNode RESULT = null; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(4/*else_clause_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 63: // when_clause ::= WHEN value_expression THEN value_expression { ParseTreeNode[] RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new ParseTreeNode[] {x, y}; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(61/*when_clause*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 62: // when_list ::= when_list when_clause { List RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; List x = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode[] y = (ParseTreeNode[])((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = x; x.add(y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(59/*when_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 61: // when_list ::= { List RESULT = null; RESULT = new ArrayList(); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(59/*when_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 60: // value_expression_opt ::= value_expression { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(15/*value_expression_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 59: // value_expression_opt ::= { ParseTreeNode RESULT = null; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(15/*value_expression_opt*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 58: // case_expression ::= CASE value_expression_opt when_list else_clause_opt END { ParseTreeNode RESULT = null; int kaseleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left; int kaseright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).right; Object kase = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).value; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; List y = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int zleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int zright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; ParseTreeNode z = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; List v = new ArrayList(); if (x != null) { v.add(x); } for (int i = 0; i < y.size(); i++) { ParseTreeNode[] exps = (ParseTreeNode[]) y.get(i); assert exps.length == 2; v.add(exps[0]); v.add(exps[1]); } if (z != null) { v.add(z); } ParseRegion region = createRegion(kaseleft, zright); if (x == null) { RESULT = new CallNode(region, "_CaseTest", Syntax.Case, v); } else { RESULT = new CallNode(region, "_CaseMatch", Syntax.Case, v); } CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(2/*case_expression*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-4)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 57: // value_expression_primary ::= case_expression { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 56: // value_expression_primary ::= NULL { ParseTreeNode RESULT = null; int nleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int nright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object n = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(nleft, nright); RESULT = LiteralNode.createNull(region); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 55: // value_expression_primary ::= LBRACE exp_list_opt RBRACE { ParseTreeNode RESULT = null; int lbraceleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int lbraceright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; Object lbrace = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int lisleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int lisright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; List lis = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int rbraceleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int rbraceright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object rbrace = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; // set built from sets/tuples ParseRegion region = createRegion(lbraceleft, rbraceright); RESULT = new CallNode(region, "{}", Syntax.Braces, lis); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 54: // value_expression_primary ::= LPAREN exp_list RPAREN { ParseTreeNode RESULT = null; int lparenleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int lparenright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; Object lparen = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int lisleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int lisright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; List lis = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int rparenleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int rparenright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object rparen = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; // Whereas ([Sales],[Time]) and () are tuples, ([Sales]) and (5) // are just expressions. ParseRegion region = createRegion(lparenleft, rparenright); RESULT = new CallNode(region, "()", Syntax.Parentheses, lis); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 53: // value_expression_primary ::= CAST LPAREN expression AS identifier RPAREN { ParseTreeNode RESULT = null; int castleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).left; int castright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).right; Object cast = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).value; int eleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int eright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; ParseTreeNode e = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int tleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int tright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; IdentifierSegment t = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int rparenleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int rparenright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object rparen = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; LiteralNode symbol = LiteralNode.createSymbol(t.getRegion(), t.getName()); ParseRegion region = createRegion(castleft, rparenright); RESULT = new CallNode(region, "CAST", Syntax.Cast, e, symbol); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 52: // value_expression_primary ::= identifier LPAREN exp_list_opt RPAREN { ParseTreeNode RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; IdentifierSegment i = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int lisleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int lisright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; List lis = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int rparenleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int rparenright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object rparen = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(ileft, rparenright); RESULT = new CallNode(region, i.getName(), Syntax.Function, lis); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 51: // value_expression_primary ::= value_expression_primary DOT identifier LPAREN exp_list_opt RPAREN { ParseTreeNode RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).right; ParseTreeNode i = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).value; int jleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int jright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; IdentifierSegment j = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int lisleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int lisright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; List lis = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int rparenleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int rparenright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object rparen = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; lis.add(0, i); ParseRegion region = createRegion(ileft, rparenright); RESULT = new CallNode(region, j.getName(), Syntax.Method, lis); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-5)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 50: // value_expression_primary ::= value_expression_primary DOT key_identifier { ParseTreeNode RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode i = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int jleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int jright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment j = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; if (i instanceof IdentifierNode) { RESULT = ((IdentifierNode) i).append(j); } else { ParseRegion region = createRegion(ileft, jright); RESULT = new CallNode( region, j.getName(), Syntax.AmpersandQuotedProperty, i); } CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 49: // value_expression_primary ::= value_expression_primary DOT quoted_identifier { ParseTreeNode RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode i = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int jleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int jright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment j = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; if (i instanceof IdentifierNode) { RESULT = ((IdentifierNode) i).append(j); } else { ParseRegion region = createRegion(ileft, jright); RESULT = new CallNode( region, j.getName(), Syntax.QuotedProperty, i); } CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 48: // value_expression_primary ::= value_expression_primary DOT unquoted_identifier { ParseTreeNode RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode i = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int jleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int jright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment j = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; if (i instanceof IdentifierNode && !parser.isFunCall(j.getName())) { RESULT = ((IdentifierNode) i).append(j); } else { ParseRegion region = createRegion(ileft, jright); RESULT = new CallNode(region, j.getName(), Syntax.Property, i); } CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 47: // value_expression_primary ::= identifier { ParseTreeNode RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment i = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new IdentifierNode(i); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 46: // value_expression_primary ::= NUMBER { ParseTreeNode RESULT = null; int dleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int dright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; BigDecimal d = (BigDecimal)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(dleft, dright); RESULT = LiteralNode.createNumeric(region, d, false); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 45: // value_expression_primary ::= STRING { ParseTreeNode RESULT = null; int sleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int sright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; String s = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(sleft, sright); RESULT = LiteralNode.createString(region, s); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(16/*value_expression_primary*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 44: // factor ::= MINUS value_expression_primary { ParseTreeNode RESULT = null; int minusleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int minusright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; Object minus = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int pleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int pright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode p = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(minusleft, pright); RESULT = new CallNode(region, "-", Syntax.Prefix, p); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(7/*factor*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 43: // factor ::= PLUS value_expression_primary { ParseTreeNode RESULT = null; int pleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int pright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode p = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = p; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(7/*factor*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 42: // factor ::= value_expression_primary { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(7/*factor*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 41: // term ::= term SOLIDUS factor { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "/", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(9/*term*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 40: // term ::= term ASTERISK factor { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "*", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(9/*term*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 39: // term ::= factor { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(9/*term*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 38: // term2 ::= term2 CONCAT term { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "||", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(10/*term2*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 37: // term2 ::= term2 MINUS term { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "-", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(10/*term2*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 36: // term2 ::= term2 PLUS term { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "+", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(10/*term2*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 35: // term2 ::= term { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(10/*term2*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 34: // term3 ::= term3 NOT IN term2 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode( region, "NOT", Syntax.Prefix, new CallNode(region, "IN", Syntax.Infix, x, y)); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 33: // term3 ::= term3 IN term2 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "IN", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 32: // term3 ::= term3 NOT MATCHES term2 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode( region, "NOT", Syntax.Prefix, new CallNode(region, "MATCHES", Syntax.Infix, x, y)); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-3)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 31: // term3 ::= term3 MATCHES term2 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "MATCHES", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 30: // term3 ::= term3 IS EMPTY { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int emptyleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int emptyright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object empty = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, emptyright); RESULT = new CallNode(region, "IS EMPTY", Syntax.Postfix, x); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 29: // term3 ::= term3 IS term2 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; // e.g. "x IS y"; but "x IS NULL" is handled elsewhere ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "IS", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 28: // term3 ::= term3 IS NULL { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int nleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int nright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; Object n = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, nright); RESULT = new CallNode(region, "IS NULL", Syntax.Postfix, x); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 27: // term3 ::= term3 comp_op term2 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int opleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int opright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; String op = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; // e.g. "1 < 5" ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, op, Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 26: // term3 ::= term2 { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(11/*term3*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 25: // term4 ::= NOT term4 { ParseTreeNode RESULT = null; int notleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int notright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; Object not = (Object)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int pleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int pright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode p = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(notleft, pright); RESULT = new CallNode(region, "NOT", Syntax.Prefix, p); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(12/*term4*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 24: // term4 ::= term3 { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(12/*term4*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 23: // term5 ::= term5 AND term4 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "AND", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(13/*term5*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 22: // term5 ::= term4 { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(13/*term5*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 21: // value_expression ::= value_expression XOR term5 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "XOR", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(14/*value_expression*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 20: // value_expression ::= value_expression OR term5 { ParseTreeNode RESULT = null; int xleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int xright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; ParseTreeNode x = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int yleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int yright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; ParseTreeNode y = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(xleft, yright); RESULT = new CallNode(region, "OR", Syntax.Infix, x, y); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(14/*value_expression*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 19: // value_expression ::= term5 { ParseTreeNode RESULT = null; // Default action for single-symbol production RESULT = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(14/*value_expression*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 18: // cube_name ::= compound_id { IdentifierNode RESULT = null; // Default action for single-symbol production RESULT = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(23/*cube_name*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 17: // compound_id ::= compound_id DOT identifier { IdentifierNode RESULT = null; int hdleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left; int hdright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).right; IdentifierNode hd = (IdentifierNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).value; int tlleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int tlright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment tl = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = hd.append(tl); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(22/*compound_id*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-2)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 16: // compound_id ::= identifier { IdentifierNode RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment i = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new IdentifierNode(i); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(22/*compound_id*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 15: // keyword ::= PROPERTIES { String RESULT = null; RESULT = "Properties"; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(29/*keyword*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 14: // keyword ::= DIMENSION { String RESULT = null; RESULT = "Dimension"; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(29/*keyword*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 13: // identifier ::= key_identifier { IdentifierSegment RESULT = null; // Default action for single-symbol production RESULT = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(30/*identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 12: // identifier ::= quoted_identifier { IdentifierSegment RESULT = null; // Default action for single-symbol production RESULT = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(30/*identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 11: // identifier ::= unquoted_identifier { IdentifierSegment RESULT = null; // Default action for single-symbol production RESULT = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(30/*identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 10: // amp_unquoted_identifier ::= AMP_UNQUOTED_ID { IdentifierSegment RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; String i = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.UNQUOTED); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(36/*amp_unquoted_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 9: // amp_quoted_identifier ::= AMP_QUOTED_ID { IdentifierSegment RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; String i = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.QUOTED); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(35/*amp_quoted_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 8: // amp_identifier ::= amp_unquoted_identifier { IdentifierSegment RESULT = null; // Default action for single-symbol production RESULT = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(34/*amp_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 7: // amp_identifier ::= amp_quoted_identifier { IdentifierSegment RESULT = null; // Default action for single-symbol production RESULT = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top)).value; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(34/*amp_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 6: // amp_identifier_list ::= amp_identifier_list amp_identifier { List RESULT = null; int listleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int listright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; List list = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment i = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; list.add(i); RESULT = list; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(37/*amp_identifier_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 5: // amp_identifier_list ::= amp_identifier { List RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; IdentifierSegment i = (IdentifierSegment)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new ArrayList(); RESULT.add(i); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(37/*amp_identifier_list*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 4: // key_identifier ::= amp_identifier_list { IdentifierSegment RESULT = null; int listleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int listright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; List list = (List)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; RESULT = new KeySegment(list); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(31/*key_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 3: // unquoted_identifier ::= keyword { IdentifierSegment RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; String i = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.UNQUOTED); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(33/*unquoted_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 2: // unquoted_identifier ::= ID { IdentifierSegment RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; String i = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.UNQUOTED); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(33/*unquoted_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 1: // quoted_identifier ::= QUOTED_ID { IdentifierSegment RESULT = null; int ileft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left; int iright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right; String i = (String)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).value; ParseRegion region = createRegion(ileft, iright); RESULT = new NameSegment(region, i, Quoting.QUOTED); CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(32/*quoted_identifier*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } return CUP$DefaultMdxParser$result; /*. . . . . . . . . . . . . . . . . . . .*/ case 0: // $START ::= statement EOF { Object RESULT = null; int start_valleft = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left; int start_valright = ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).right; ParseTreeNode start_val = (ParseTreeNode)((java_cup.runtime.Symbol) CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).value; RESULT = start_val; CUP$DefaultMdxParser$result = new java_cup.runtime.Symbol(0/*$START*/, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-1)).left, ((java_cup.runtime.Symbol)CUP$DefaultMdxParser$stack.elementAt(CUP$DefaultMdxParser$top-0)).right, RESULT); } /* ACCEPT */ CUP$DefaultMdxParser$parser.done_parsing(); return CUP$DefaultMdxParser$result; /* . . . . . .*/ default: throw new Exception( "Invalid action number found in internal parse table"); } } } olap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/Scanner.java0000644000175000017500000010024711707254776023155 0ustar drazzibdrazzib/* // $Id: Scanner.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx.parser.impl; import org.olap4j.mdx.ParseRegion; import org.olap4j.mdx.parser.MdxParseException; import java_cup.runtime.Symbol; import java.io.IOException; import java.math.BigDecimal; import java.util.*; /** * Lexical analyzer for MDX. * *

      NOTE: This class is not part of the public olap4j API. * * @version $Id: Scanner.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ class Scanner { /** single lookahead character */ protected int nextChar; /** next lookahead character */ private int lookaheadChars[] = new int[16]; private int firstLookaheadChar = 0; private int lastLookaheadChar = 0; private Map reservedWordIds; private int iMaxResword; private String[] reservedWords; protected boolean debug; /** lines[x] is the start of the x'th line */ private final List lines = new ArrayList(); /** number of times advance() has been called */ private int iChar; /** end of previous token */ private int iPrevChar; /** previous symbol returned */ private int previousSymbol; private boolean inFormula; /** * Comment delimiters. Modify this list to support other comment styles. */ private static final String[][] commentDelim = { {"//", null}, {"--", null}, {"/*", "*/"} }; /** * Whether to allow nested comments. */ private static final boolean allowNestedComments = true; /** * The {@link java.math.BigDecimal} value 0. * Note that BigDecimal.ZERO does not exist until JDK 1.5. */ private static final BigDecimal BigDecimalZero = BigDecimal.valueOf(0); /** * Creates a Scanner. * * @param debug Whether to populate debug messages. */ Scanner(boolean debug) { this.debug = debug; } /** * Returns the current nested comments state. */ public static boolean getNestedCommentsState() { return allowNestedComments; } /** * Returns the list of comment delimiters. */ public static String[][] getCommentDelimiters() { return commentDelim; } /** * Advance input by one character, setting {@link #nextChar}. */ private void advance() throws java.io.IOException { if (firstLookaheadChar == lastLookaheadChar) { // We have nothing in the lookahead buffer. nextChar = getChar(); } else { // We have called lookahead(); advance to the next character it got. nextChar = lookaheadChars[firstLookaheadChar++]; if (firstLookaheadChar == lastLookaheadChar) { firstLookaheadChar = 0; lastLookaheadChar = 0; } } if (nextChar == '\012') { lines.add(iChar); } iChar++; } /** Peek at the character after {@link #nextChar} without advancing. */ private int lookahead() throws java.io.IOException { return lookahead(1); } /** * Peeks at the character n after {@link #nextChar} without advancing. * lookahead(0) returns the current char (nextChar). * lookahead(1) returns the next char (was lookaheadChar, same as lookahead()); */ private int lookahead(int n) throws java.io.IOException { if (n == 0) { return nextChar; } else { // if the desired character not in lookahead buffer, read it in if (n > lastLookaheadChar - firstLookaheadChar) { int len=lastLookaheadChar - firstLookaheadChar; int t[]; // make sure we do not go off the end of the buffer if (n + firstLookaheadChar > lookaheadChars.length) { if (n > lookaheadChars.length) { // the array is too small; make it bigger and shift // everything to the beginning. t=new int[n * 2]; } else { // the array is big enough, so just shift everything // to the beginning of it. t = lookaheadChars; } System.arraycopy( lookaheadChars, firstLookaheadChar, t, 0, len); lookaheadChars = t; firstLookaheadChar = 0; lastLookaheadChar = len; } // read ahead enough while (n > lastLookaheadChar - firstLookaheadChar) { lookaheadChars[lastLookaheadChar++] = getChar(); } } return lookaheadChars[n - 1 + firstLookaheadChar]; } } /** Read a character from input, returning -1 if end of input. */ protected int getChar() throws java.io.IOException { return System.in.read(); } /** Initialize the scanner */ public void init() throws java.io.IOException { initReswords(); lines.clear(); iChar = iPrevChar = 0; advance(); } private void initResword(int id, String s) { reservedWordIds.put(s, id); if (id > iMaxResword) { iMaxResword = id; } } /** * Initializes the table of reserved words. */ private void initReswords() { // This list generated by piping the 'terminal' declaration in mdx.cup // through: // grep -list // | // sed -e 's/,//' | // awk '{printf "initResword(%20s,%c%s%c);",$1,34,$1,34}' reservedWordIds = new HashMap(); iMaxResword = 0; // initResword(DefaultMdxParserSym.ALL ,"ALL"); initResword(DefaultMdxParserSym.AND ,"AND"); initResword(DefaultMdxParserSym.AS ,"AS"); // initResword(DefaultMdxParserSym.ASC ,"ASC"); initResword(DefaultMdxParserSym.AXIS ,"AXIS"); // initResword(DefaultMdxParserSym.BACK_COLOR ,"BACK_COLOR"); // initResword(DefaultMdxParserSym.BASC ,"BASC"); // initResword(DefaultMdxParserSym.BDESC ,"BDESC"); initResword(DefaultMdxParserSym.CAST ,"CAST"); // mondrian extension initResword(DefaultMdxParserSym.CASE ,"CASE"); initResword(DefaultMdxParserSym.CELL ,"CELL"); // initResword(DefaultMdxParserSym.CELL_ORDINAL ,"CELL_ORDINAL"); initResword(DefaultMdxParserSym.CHAPTERS ,"CHAPTERS"); // initResword(DefaultMdxParserSym.CHILDREN ,"CHILDREN"); initResword(DefaultMdxParserSym.COLUMNS ,"COLUMNS"); // initResword(DefaultMdxParserSym.DESC ,"DESC"); initResword(DefaultMdxParserSym.DIMENSION ,"DIMENSION"); initResword(DefaultMdxParserSym.ELSE ,"ELSE"); initResword(DefaultMdxParserSym.EMPTY ,"EMPTY"); initResword(DefaultMdxParserSym.END ,"END"); // initResword(DefaultMdxParserSym.FIRSTCHILD ,"FIRSTCHILD"); // initResword(DefaultMdxParserSym.FIRSTSIBLING ,"FIRSTSIBLING"); // initResword(DefaultMdxParserSym.FONT_FLAGS ,"FONT_FLAGS"); // initResword(DefaultMdxParserSym.FONT_NAME ,"FONT_NAME"); // initResword(DefaultMdxParserSym.FONT_SIZE ,"FONT_SIZE"); // initResword(DefaultMdxParserSym.FORE_COLOR ,"FORE_COLOR"); // initResword(DefaultMdxParserSym.FORMATTED_VALUE ,"FORMATTED_VALUE"); // initResword(DefaultMdxParserSym.FORMAT_STRING ,"FORMAT_STRING"); initResword(DefaultMdxParserSym.FROM ,"FROM"); initResword(DefaultMdxParserSym.IS ,"IS"); initResword(DefaultMdxParserSym.IN ,"IN"); // initResword(DefaultMdxParserSym.LAG ,"LAG"); // initResword(DefaultMdxParserSym.LASTCHILD ,"LASTCHILD"); // initResword(DefaultMdxParserSym.LASTSIBLING ,"LASTSIBLING"); // initResword(DefaultMdxParserSym.LEAD ,"LEAD"); initResword(DefaultMdxParserSym.MATCHES ,"MATCHES"); initResword(DefaultMdxParserSym.MEMBER ,"MEMBER"); // initResword(DefaultMdxParserSym.MEMBERS ,"MEMBERS"); // initResword(DefaultMdxParserSym.NEXTMEMBER ,"NEXTMEMBER"); initResword(DefaultMdxParserSym.NON ,"NON"); initResword(DefaultMdxParserSym.NOT ,"NOT"); initResword(DefaultMdxParserSym.NULL ,"NULL"); initResword(DefaultMdxParserSym.ON ,"ON"); initResword(DefaultMdxParserSym.OR ,"OR"); initResword(DefaultMdxParserSym.PAGES ,"PAGES"); // initResword(DefaultMdxParserSym.PARENT ,"PARENT"); // initResword(DefaultMdxParserSym.PREVMEMBER ,"PREVMEMBER"); initResword(DefaultMdxParserSym.PROPERTIES ,"PROPERTIES"); // initResword(DefaultMdxParserSym.RECURSIVE ,"RECURSIVE"); initResword(DefaultMdxParserSym.ROWS ,"ROWS"); initResword(DefaultMdxParserSym.SECTIONS ,"SECTIONS"); initResword(DefaultMdxParserSym.SELECT ,"SELECT"); initResword(DefaultMdxParserSym.SET ,"SET"); // initResword(DefaultMdxParserSym.SOLVE_ORDER ,"SOLVE_ORDER"); initResword(DefaultMdxParserSym.THEN ,"THEN"); // initResword(DefaultMdxParserSym.VALUE ,"VALUE"); initResword(DefaultMdxParserSym.WHEN ,"WHEN"); initResword(DefaultMdxParserSym.WHERE ,"WHERE"); initResword(DefaultMdxParserSym.WITH ,"WITH"); initResword(DefaultMdxParserSym.XOR ,"XOR"); reservedWords = new String[iMaxResword + 1]; for (Map.Entry entry : reservedWordIds.entrySet()) { reservedWords[entry.getValue()] = entry.getKey(); } } /** return the name of the reserved word whose token code is "i" */ public String lookupReserved(int i) { return reservedWords[i]; } private Symbol makeSymbol(int id, Object o) { int iPrevPrevChar = iPrevChar; this.iPrevChar = iChar; this.previousSymbol = id; return new Symbol(id, iPrevPrevChar, iChar, o); } /** * Creates a token representing a numeric literal. * * @param mantissa The digits of the number * @param exponent The base-10 exponent of the number * @return number literal token */ private Symbol makeNumber(BigDecimal mantissa, int exponent) { BigDecimal d = mantissa.movePointRight(exponent); return makeSymbol(DefaultMdxParserSym.NUMBER, d); } private Symbol makeId(String s, boolean quoted, boolean ampersand) { final int id; if (quoted) { if (ampersand) { id = DefaultMdxParserSym.AMP_QUOTED_ID; } else { id = DefaultMdxParserSym.QUOTED_ID; } } else { if (ampersand) { id = DefaultMdxParserSym.AMP_UNQUOTED_ID; } else { id = DefaultMdxParserSym.ID; } } return makeSymbol(id, s); } /** * Creates a token representing a reserved word. * * @param i Token code * @return Token */ private Symbol makeRes(int i) { return makeSymbol(i, reservedWords[i]); } /** * Creates a token. * * @param i Token code * @param s Text of the token * @return Token */ private Symbol makeToken(int i, String s) { return makeSymbol(i, s); } /** * Creates a token representing a string literal. * * @param s String * @return String token */ private Symbol makeString(String s) { if (inFormula) { inFormula = false; return makeSymbol(DefaultMdxParserSym.FORMULA_STRING, s); } else { return makeSymbol(DefaultMdxParserSym.STRING, s); } } /** * Discards all characters until the end of the current line. */ private void skipToEOL() throws IOException { while (nextChar != -1 && nextChar != '\012') { advance(); } } /** * Eats a delimited comment. * The type of delimiters are kept in commentDelim. The current * comment type is indicated by commentType. * end of file terminates a comment without error. */ private void skipComment( final String startDelim, final String endDelim) throws IOException { int depth = 1; // skip the starting delimiter for (int x = 0; x < startDelim.length(); x++) { advance(); } for (;;) { if (nextChar == -1) { return; } else if (checkForSymbol(endDelim)) { // eat the end delimiter for (int x = 0; x < endDelim.length(); x++) { advance(); } if (--depth == 0) { return; } } else if (allowNestedComments && checkForSymbol(startDelim)) { // eat the nested start delimiter for (int x = 0; x < startDelim.length(); x++) { advance(); } depth++; } else { advance(); } } } /** * If the next tokens are comments, skip over them. */ private void searchForComments() throws IOException { // eat all following comments boolean foundComment; do { foundComment = false; for (String[] aCommentDelim : commentDelim) { if (checkForSymbol(aCommentDelim[0])) { if (aCommentDelim[1] == null) { foundComment = true; skipToEOL(); } else { foundComment = true; skipComment(aCommentDelim[0], aCommentDelim[1]); } } } } while (foundComment); } /** * Checks if the next symbol is the supplied string */ private boolean checkForSymbol(final String symb) throws IOException { for (int x = 0; x < symb.length(); x++) { if (symb.charAt(x) != lookahead(x)) { return false; } } return true; } /** * Recognizes and returns the next complete token. */ public Symbol next_token() throws IOException { StringBuilder id; boolean ampersandId = false; for (;;) { searchForComments(); mainSwitch: switch (nextChar) { case '.': switch (lookahead()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // We're looking at the '.' on the start of a number, // e.g. .1; fall through to parse a number. break; default: advance(); return makeToken(DefaultMdxParserSym.DOT, "."); } // fall through case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // Parse a number. Valid examples include 1, 1.2, 0.1, .1, // 1e2, 1E2, 1e-2, 1e+2. Invalid examples include e2, 1.2.3, // 1e2e3, 1e2.3. // // Signs preceding numbers (e.g. -1, +1E-5) are valid, but are // handled by the parser. // BigDecimal n = BigDecimalZero; int digitCount = 0, exponent = 0; boolean positive = true; BigDecimal mantissa = BigDecimalZero; State state = State.leftOfPoint; for (;;) { switch (nextChar) { case '.': switch (state) { case leftOfPoint: state = State.rightOfPoint; mantissa = n; n = BigDecimalZero; digitCount = 0; positive = true; advance(); break; // Error: we are seeing a point in the exponent // (e.g. 1E2.3 or 1.2E3.4) or a second point in the // mantissa (e.g. 1.2.3). Return what we've got // and let the parser raise the error. case rightOfPoint: mantissa = mantissa.add( n.movePointRight(-digitCount)); return makeNumber(mantissa, exponent); case inExponent: if (!positive) { n = n.negate(); } exponent = n.intValue(); return makeNumber(mantissa, exponent); } break; case 'E': case 'e': switch (state) { case inExponent: // Error: we are seeing an 'e' in the exponent // (e.g. 1.2e3e4). Return what we've got and let // the parser raise the error. if (!positive) { n = n.negate(); } exponent = n.intValue(); return makeNumber(mantissa, exponent); case leftOfPoint: mantissa = n; break; default: mantissa = mantissa.add( n.movePointRight(-digitCount)); break; } digitCount = 0; n = BigDecimalZero; positive = true; advance(); state = State.inExponent; break; case'0': case'1': case'2': case'3': case'4': case'5': case'6': case'7': case'8': case'9': n = n.movePointRight(1); n = n.add(BigDecimal.valueOf(nextChar - '0')); digitCount++; advance(); break; case '+': case '-': if (state == State.inExponent && digitCount == 0) { // We're looking at the sign after the 'e'. positive = !positive; advance(); break; } // fall through - end of number default: // Reached end of number. switch (state) { case leftOfPoint: mantissa = n; break; case rightOfPoint: mantissa = mantissa.add( n.movePointRight(-digitCount)); break; default: if (!positive) { n = n.negate(); } exponent = n.intValue(); break; } return makeNumber(mantissa, exponent); } } case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case '$': /* parse an identifier */ id = new StringBuilder(); for (;;) { id.append((char) nextChar); advance(); switch (nextChar) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '_': case '$': break; default: String strId = id.toString(); Integer i = reservedWordIds.get( strId.toUpperCase()); if (i == null) { // identifier return makeId(strId, false, ampersandId); } else { // reserved word return makeRes(i); } } } case '&': advance(); switch (nextChar) { case '[': // fall through to parse a delimited identifier ampersandId = true; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': // fall into logic to create identifer ampersandId = true; break mainSwitch; default: // error return makeToken(DefaultMdxParserSym.UNKNOWN, "&"); } case '[': /* parse a delimited identifier */ id = new StringBuilder(); for (;;) { advance(); switch (nextChar) { case ']': advance(); if (nextChar == ']') { // ] escaped with ] - just take one id.append(']'); break; } else { // end of identifier if (ampersandId) { ampersandId = false; return makeId(id.toString(), true, true); } else { return makeId(id.toString(), true, false); } } case -1: if (ampersandId) { ampersandId = false; return makeId(id.toString(), true, true); } else { return makeId(id.toString(), true, false); } default: id.append((char) nextChar); } } case ':': advance(); return makeToken(DefaultMdxParserSym.COLON, ":"); case ',': advance(); return makeToken(DefaultMdxParserSym.COMMA, ","); case '=': advance(); return makeToken(DefaultMdxParserSym.EQ, "="); case '<': advance(); switch (nextChar) { case '>': advance(); return makeToken(DefaultMdxParserSym.NE, "<>"); case '=': advance(); return makeToken(DefaultMdxParserSym.LE, "<="); default: return makeToken(DefaultMdxParserSym.LT, "<"); } case '>': advance(); switch (nextChar) { case '=': advance(); return makeToken(DefaultMdxParserSym.GE, ">="); default: return makeToken(DefaultMdxParserSym.GT, ">"); } case '{': advance(); return makeToken(DefaultMdxParserSym.LBRACE, "{"); case '(': advance(); return makeToken(DefaultMdxParserSym.LPAREN, "("); case '}': advance(); return makeToken(DefaultMdxParserSym.RBRACE, "}"); case ')': advance(); return makeToken(DefaultMdxParserSym.RPAREN, ")"); case '+': advance(); return makeToken(DefaultMdxParserSym.PLUS, "+"); case '-': advance(); return makeToken(DefaultMdxParserSym.MINUS, "-"); case '*': advance(); return makeToken(DefaultMdxParserSym.ASTERISK, "*"); case '/': advance(); return makeToken(DefaultMdxParserSym.SOLIDUS, "/"); case '|': advance(); switch (nextChar) { case '|': advance(); return makeToken(DefaultMdxParserSym.CONCAT, "||"); default: return makeToken(DefaultMdxParserSym.UNKNOWN, "|"); } case '"': /* parse a double-quoted string */ id = new StringBuilder(); for (;;) { advance(); switch (nextChar) { case '"': advance(); if (nextChar == '"') { // " escaped with " id.append('"'); break; } else { // end of string return makeString(id.toString()); } case -1: return makeString(id.toString()); default: id.append((char) nextChar); } } case '\'': if (previousSymbol == DefaultMdxParserSym.AS) { inFormula = true; } /* parse a single-quoted string */ id = new StringBuilder(); for (;;) { advance(); switch (nextChar) { case '\'': advance(); if (nextChar == '\'') { // " escaped with " id.append('\''); break; } else { // end of string return makeString(id.toString()); } case -1: return makeString(id.toString()); default: id.append((char) nextChar); } } case -1: // we're done return makeToken(DefaultMdxParserSym.EOF, "EOF"); default: // If it's whitespace, skip over it. if (nextChar <= Character.MAX_VALUE && Character.isWhitespace(nextChar)) { // fall through } else { // everything else is an error throw new MdxParseException( createRegion(iPrevChar, iChar), "Unexpected character '" + (char) nextChar + "'"); } case ' ': case '\t': case '\n': case '\r': // whitespace can be ignored iPrevChar = iChar; advance(); break; } } } /** * Creates a region from a start and end point. * Called by {@link DefaultMdxParser#syntax_error}. */ ParseRegion createRegion(final int left, final int right) { int target = left; int line = -1; int lineEnd = 0; int lineStart; do { line++; lineStart = lineEnd; lineEnd = Integer.MAX_VALUE; if (line < lines.size()) { lineEnd = lines.get(line); } } while (lineEnd < target); int startLine = line; int startColumn = target - lineStart; if (right == left) { return new ParseRegion(startLine + 1, startColumn + 1); } target = right - 1; if (target > left) --target; // don't know why line = -1; lineEnd = 0; do { line++; lineStart = lineEnd; lineEnd = Integer.MAX_VALUE; if (line < lines.size()) { lineEnd = lines.get(line); } } while (lineEnd < target); int endLine = line; int endColumn = target - lineStart; return new ParseRegion( startLine + 1, startColumn + 1, endLine + 1, endColumn + 1); } private enum State { leftOfPoint, rightOfPoint, inExponent, } } // End Scanner.java olap4j-1.0.1.500/src/org/olap4j/mdx/parser/impl/DefaultMdxParserImpl.java0000644000175000017500000000404511707254776025617 0ustar drazzibdrazzib/* // $Id: DefaultMdxParserImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx.parser.impl; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.mdx.SelectNode; import org.olap4j.mdx.parser.MdxParser; /** * Default implementation of {@link org.olap4j.mdx.parser.MdxParser MDX Parser}. * * @author jhyde * @version $Id: DefaultMdxParserImpl.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public class DefaultMdxParserImpl implements MdxParser { private boolean debug = false; private final FunTable funTable = new FunTable() { public boolean isProperty(String s) { return s.equals("CHILDREN"); } }; /** * Creates a DefaultMdxParserImpl. */ public DefaultMdxParserImpl() { super(); } public SelectNode parseSelect(String mdx) { return new DefaultMdxParser().parseSelect( mdx, debug, funTable); } public ParseTreeNode parseExpression(String mdx) { return new DefaultMdxParser().parseExpression( mdx, debug, funTable); } interface FunTable { boolean isProperty(String s); } } // End DefaultMdxParserImpl.java olap4j-1.0.1.500/src/org/olap4j/mdx/parser/MdxParser.java0000644000175000017500000000564111707254776022532 0ustar drazzibdrazzib/* // $Id: MdxParser.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx.parser; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.mdx.SelectNode; /** * Parser for the MDX query language. * *

      A parser is reusable but not reentrant: you can call {@link #parseSelect} * and {@link #parseExpression} several times, but not at the same time * from different threads. * * @see MdxParserFactory * * @author jhyde * @version $Id: MdxParser.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface MdxParser { /** * Parses an MDX Select statement and returns the {@link SelectNode} at the * root of the parse tree. * *

      In order to be parsed successfully, the expression must be * syntactically correct but does not need to be valid. (Syntactic * correctness and validity are described further in the description of * {@link #parseExpression(String)}.) * * @param mdx MDX query string * @return Parse tree */ SelectNode parseSelect(String mdx); /** * Parses an MDX expression and returns a parse tree. * *

      An expression is a combination of operators and operands, which can * occur in many places inside an MDX query, such as the definition of a * calculated member or an axis. * *

      In order to be parsed successfully, the expression must be * syntactically correct but does not need to be valid. * For example, * *

      (1 + (2 + 3)
      * * is syntactically incorrect, * because there are more open parentheses "(" than close parentheses ")", * and the parser will give an error. Conversely, * *
      (1 + [Measures].[Bad Measure])
      * * is syntactically correct, and the parser * will successfully create a parse tree, even if * [Measures].[Bad Measure] does not exist. * * @param mdx MDX expression * @return Parse tree */ ParseTreeNode parseExpression(String mdx); } // End MdxParser.java olap4j-1.0.1.500/src/org/olap4j/mdx/PropertyValueNode.java0000644000175000017500000000574411707255000022741 0ustar drazzibdrazzib/* // $Id: PropertyValueNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.type.Type; /** * Parse tree node representing a property-value pair. * *

      Property-value pairs are used to define properties of calculated members. * For example, in * *

      * WITH MEMBER [Measures].[Foo] AS ' [Measures].[Unit Sales] ',
      *   FORMAT_STRING = 'Bold',
      *   SOLVE_ORDER = 2
      * SELECT ...
      *
      * * there are two property-value pairs FORMAT_STRING and SOLVE_ORDER. * * @version $Id: PropertyValueNode.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class PropertyValueNode implements ParseTreeNode { private final ParseRegion region; private final String name; private ParseTreeNode expression; /** * Creates a PropertyValueNode. * * @param region Region of source code * @param name Name of property * @param expression Expression for value of property (often a literal) */ public PropertyValueNode( ParseRegion region, String name, ParseTreeNode expression) { this.region = region; this.name = name; this.expression = expression; } public ParseRegion getRegion() { return region; } public Type getType() { return expression.getType(); } /** * Returns the expression by which the value of the property is derived. * * @return the expression by which the value of the property is derived */ public ParseTreeNode getExpression() { return expression; } /** * Returns the name of the property * * @return name of the property */ public String getName() { return name; } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public void unparse(ParseTreeWriter writer) { writer.getPrintWriter().print(name + " = "); expression.unparse(writer); } public PropertyValueNode deepCopy() { return new PropertyValueNode( this.region, this.name, this.expression.deepCopy()); } } // End PropertyValueNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/ParseTreeVisitor.java0000644000175000017500000001256311707255000022561 0ustar drazzibdrazzib/* // $Id: ParseTreeVisitor.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; /** * Interface for a visitor to an MDX parse tree. * *

      Together with the * {@link org.olap4j.mdx.ParseTreeNode#accept(ParseTreeVisitor)} method, an * class implementing this interface implements a visitor pattern, to allow * an algorithm to efficiently traverse a parse tree and perform an action at * each node dependent upon the type of each node. * * @author jhyde * @version $Id: ParseTreeVisitor.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jul 21, 2006 */ public interface ParseTreeVisitor { /** * Visits a select statement. * * @param selectNode Node representing a select statement * * @return value yielded by visiting the node * * @see SelectNode#accept(ParseTreeVisitor) */ T visit(SelectNode selectNode); /** * Visits an axis of a select statement. * * @param axis Node representing an axis * * @return value yielded by visiting the node * * @see AxisNode#accept(ParseTreeVisitor) */ T visit(AxisNode axis); /** * Visits a member declaration. * * @param calcMemberNode Node representing a member declaration * * @return value yielded by visiting the node * * @see WithMemberNode#accept(ParseTreeVisitor) */ T visit(WithMemberNode calcMemberNode); /** * Visits a set declaration. * * @param calcSetNode Node representing a set declaration * * @return value yielded by visiting the node * * @see WithSetNode#accept(ParseTreeVisitor) */ T visit(WithSetNode calcSetNode); /** * Visits a call to an operator or function. * * @param call Node representing a call to an operator or function * * @see CallNode#accept(ParseTreeVisitor) * * @return value yielded by visiting the node */ T visit(CallNode call); /** * Visits an identifier. * * @param id Node representing an identifier * * @return value yielded by visiting the node * * @see IdentifierNode#accept(ParseTreeVisitor) */ T visit(IdentifierNode id); /** * Visits a parameter. * * @param parameterNode Node representing use of a parameter * * @return value yielded by visiting the node * * @see ParameterNode#accept(ParseTreeVisitor) */ T visit(ParameterNode parameterNode); /** * Visits a use of a {@link org.olap4j.metadata.Cube} * in a select statement. * * @param cubeNode Node representing a use of a Cube * * @return value yielded by visiting the node * * @see CubeNode#accept(ParseTreeVisitor) */ T visit(CubeNode cubeNode); /** * Visits a use of a {@link org.olap4j.metadata.Dimension} * in a select statement. * * @param dimensionNode Node representing a use of a Dimension * * @return value yielded by visiting the node * * @see DimensionNode#accept(ParseTreeVisitor) */ T visit(DimensionNode dimensionNode); /** * Visits a use of a {@link org.olap4j.metadata.Hierarchy} * in a select statement. * * @param hierarchyNode Node representing a use of a Hierarchy * * @return value yielded by visiting the node * * @see HierarchyNode#accept(ParseTreeVisitor) */ T visit(HierarchyNode hierarchyNode); /** * Visits a use of a {@link org.olap4j.metadata.Level} * in a select statement. * * @param levelNode Node representing a use of a Level * * @return value yielded by visiting the node * * @see LevelNode#accept(ParseTreeVisitor) */ T visit(LevelNode levelNode); /** * Visits a use of a {@link org.olap4j.metadata.Member} * in a select statement. * * @param memberNode Node representing a use of a Member * * @return value yielded by visiting the node * * @see MemberNode#accept(ParseTreeVisitor) */ T visit(MemberNode memberNode); /** * Visits a literal. * * @param literalNode Node representing a Literal * * @return value yielded by visiting the node * * @see LiteralNode#accept(ParseTreeVisitor) */ T visit(LiteralNode literalNode); /** * Visits a property-value pair. * * @param propertyValueNode Node representing a property-value pair * * @return value yielded by visiting the node * * @see PropertyValueNode#accept(ParseTreeVisitor) */ T visit(PropertyValueNode propertyValueNode); } // End ParseTreeVisitor.java olap4j-1.0.1.500/src/org/olap4j/mdx/KeySegment.java0000644000175000017500000000570111707255000021356 0ustar drazzibdrazzib/* // $Id: KeySegment.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.impl.UnmodifiableArrayList; import java.util.List; /** * Segment that represents a key or compound key. * *

      Such a segment appears in an identifier with each component prefixed * with "&". For example, in the identifier * "[Customer].[State].&[WA]&[USA]", the third segment is * a compound key whose parts are "{@code WA}" and "{@code USA}". * * @see org.olap4j.mdx.NameSegment * * @version $Id: KeySegment.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class KeySegment implements IdentifierSegment { private final List subSegmentList; /** * Creates a KeySegment with one or more sub-segments. * * @param subSegments Array of sub-segments */ public KeySegment(NameSegment... subSegments) { if (subSegments.length < 1) { throw new IllegalArgumentException(); } this.subSegmentList = UnmodifiableArrayList.asCopyOf(subSegments); } /** * Creates a KeySegment a list of sub-segments. * * @param subSegmentList List of sub-segments */ public KeySegment(List subSegmentList) { if (subSegmentList.size() < 1) { throw new IllegalArgumentException(); } this.subSegmentList = new UnmodifiableArrayList( subSegmentList.toArray( new NameSegment[subSegmentList.size()])); } public String toString() { final StringBuilder buf = new StringBuilder(); toString(buf); return buf.toString(); } public void toString(StringBuilder buf) { for (IdentifierSegment segment : subSegmentList) { buf.append('&'); segment.toString(buf); } } public ParseRegion getRegion() { return IdentifierNode.sumSegmentRegions(subSegmentList); } public Quoting getQuoting() { return Quoting.KEY; } public String getName() { return null; } public List getKeyParts() { return subSegmentList; } } // End KeySegment.java olap4j-1.0.1.500/src/org/olap4j/mdx/DefaultMdxValidatorImpl.java0000644000175000017500000001541611707255000024034 0ustar drazzibdrazzib/* // $Id: DefaultMdxValidatorImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.OlapException; import org.olap4j.mdx.parser.MdxValidator; import org.olap4j.type.Type; import org.olap4j.type.TypeUtil; import java.util.List; import java.util.Stack; /** * Visitor which passes over a tree of MDX nodes, checks that they are valid, * and assigns a type to each. * *

      NOTE: This class is experimental. Not part of the public olap4j API. * * @author jhyde * @version $Id: DefaultMdxValidatorImpl.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ class DefaultMdxValidatorImpl implements ParseTreeVisitor, MdxValidator { private Stack scalarStack = new Stack(); private final SelectNode selectNode; /** * Creates a DefaultMdxValidatorImpl. * * @param selectNode Root of parse tree */ protected DefaultMdxValidatorImpl(SelectNode selectNode) { this.selectNode = selectNode; } public SelectNode validateSelect(SelectNode selectNode) throws OlapException { return null; } public ParseTreeNode visit(SelectNode selectNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(AxisNode axis) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(WithMemberNode withMemberNode) { ParseTreeNode expression = acceptScalar(withMemberNode.getExpression()); withMemberNode.setExpression(expression); final Type type = expression.getType(); if (!TypeUtil.canEvaluate(type)) { throw new RuntimeException( "'Member expression '" + MdxUtil.toString(expression) + "' must not be a set'"); } for (PropertyValueNode prop : withMemberNode.getMemberPropertyList()) { prop.accept(this); } return withMemberNode; } public ParseTreeNode visit(WithSetNode withSetNode) { ParseTreeNode expression = acceptScalar(withSetNode.getExpression()); withSetNode.setExpression(expression); final Type type = expression.getType(); if (!TypeUtil.isSet(type)) { final IdentifierNode id = withSetNode.getIdentifier(); final String idString = MdxUtil.toString(id); throw new RuntimeException( "Set expression '" + idString + "' must be a set"); } return withSetNode; } public ParseTreeNode visit(CallNode call) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(IdentifierNode id) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(ParameterNode parameterNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(CubeNode cubeNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(DimensionNode dimensionNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(HierarchyNode hierarchyNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(LevelNode levelExpr) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(MemberNode memberNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(LiteralNode literalNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public ParseTreeNode visit(PropertyValueNode propertyValueNode) { if (false) { return null; } throw new UnsupportedOperationException(); } public void accept(AxisNode axis) { ParseTreeNode exp = axis.getExpression().accept(this); final Type type = exp.getType(); if (!TypeUtil.isSet(type)) { throw new RuntimeException( "Axis '" + axis.getAxis().name() + "' expression is not a set"); } } public ParseTreeNode acceptScalar(ParseTreeNode node) { scalarStack.push(Boolean.TRUE); try { return node.accept(this); } finally { scalarStack.pop(); } } // from IdentifierNode public ParseTreeNode accept(IdentifierNode identifier) { if (identifier.getSegmentList().size() == 1) { final IdentifierSegment s = identifier.getSegmentList().get(0); if (s.getQuoting() == Quoting.UNQUOTED && isReserved(s.getName())) { return LiteralNode.createSymbol( s.getRegion(), s.getName().toUpperCase()); } } final ParseTreeNode element = lookup(selectNode, identifier.getSegmentList(), true); if (element == null) { return null; } return element.accept(this); } public ParseTreeNode accept(LiteralNode literalNode) { return literalNode; } public boolean isReserved(String name) { // todo: implement throw new UnsupportedOperationException(); } private ParseTreeNode lookup( SelectNode select, List segments, boolean allowProp) { // todo: something like /* final Exp element = Util.lookup(select, names, true); */ throw new UnsupportedOperationException(); } } // End DefaultMdxValidatorImpl.java olap4j-1.0.1.500/src/org/olap4j/mdx/LevelNode.java0000644000175000017500000000452611707255000021164 0ustar drazzibdrazzib/* // $Id: LevelNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.metadata.Level; import org.olap4j.type.LevelType; import org.olap4j.type.Type; /** * Usage of a {@link org.olap4j.metadata.Level} as an expression in an MDX * parse tree. * * @author jhyde * @version $Id: LevelNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public class LevelNode implements ParseTreeNode { private final ParseRegion region; private final Level level; /** * Creates a LevelNode. * * @param region Region of source code * @param level Level which is used in the expression */ public LevelNode( ParseRegion region, Level level) { this.region = region; this.level = level; } public ParseRegion getRegion() { return region; } /** * Returns the Level used in this expression. * * @return level used in this expression */ public Level getLevel() { return level; } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public Type getType() { return new LevelType( level.getDimension(), level.getHierarchy(), level); } public void unparse(ParseTreeWriter writer) { writer.getPrintWriter().print(level.getUniqueName()); } public String toString() { return level.getUniqueName(); } public LevelNode deepCopy() { // LevelNode is immutable return this; } } // End LevelNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/NameSegment.java0000644000175000017500000000565511707255000021516 0ustar drazzibdrazzib/* // $Id: NameSegment.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.impl.Olap4jUtil; import java.util.List; /** * Component in a compound identifier that describes the name of an object. * Optionally, the name is quoted in brackets. * * @see KeySegment * * @version $Id: NameSegment.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class NameSegment implements IdentifierSegment { final String name; final Quoting quoting; private final ParseRegion region; /** * Creates a segment with the given quoting and region. * * @param region Region of source code * @param name Name * @param quoting Quoting style */ public NameSegment( ParseRegion region, String name, Quoting quoting) { this.region = region; this.name = name; this.quoting = quoting; if (name == null) { throw new NullPointerException(); } if (!(quoting == Quoting.QUOTED || quoting == Quoting.UNQUOTED)) { throw new IllegalArgumentException(); } } /** * Creates a quoted segment, "[name]". * * @param name Name of segment */ public NameSegment(String name) { this(null, name, Quoting.QUOTED); } public String toString() { switch (quoting) { case UNQUOTED: return name; case QUOTED: return IdentifierNode.quoteMdxIdentifier(name); default: throw Olap4jUtil.unexpected(quoting); } } public void toString(StringBuilder buf) { switch (quoting) { case UNQUOTED: buf.append(name); return; case QUOTED: IdentifierNode.quoteMdxIdentifier(name, buf); return; default: throw Olap4jUtil.unexpected(quoting); } } public ParseRegion getRegion() { return region; } public String getName() { return name; } public Quoting getQuoting() { return quoting; } public List getKeyParts() { return null; } } // End NameSegment.java olap4j-1.0.1.500/src/org/olap4j/mdx/IdentifierSegment.java0000644000175000017500000000607311707255000022713 0ustar drazzibdrazzib/* // $Id: IdentifierSegment.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import java.util.List; /** * Component in a compound identifier. It is described by its name and how * the name is quoted. * *

      For example, the identifier * [Store].USA.[New Mexico].&[45] has four segments:

        *
      • "Store", {@link Quoting#QUOTED}
      • *
      • "USA", {@link Quoting#UNQUOTED}
      • *
      • "New Mexico", {@link Quoting#QUOTED}
      • *
      • "45", {@link Quoting#KEY}
      • *
      * *

      QUOTED and UNQUOTED segments are represented using a * {@link NameSegment NameSegment}; * KEY segments are represented using a * {@link KeySegment KeySegment}. * *

      To parse an identifier into a list of segments, use the method * {@link org.olap4j.mdx.IdentifierNode#parseIdentifier(String)} and then call * {@link org.olap4j.mdx.IdentifierNode#getSegmentList()} on the resulting * node.

      * * @version $Id: IdentifierSegment.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public interface IdentifierSegment { /** * Returns a string representation of this Segment. * *

      For example, "[Foo]", "&[123]", "Abc". * * @return String representation of this Segment */ String toString(); /** * Appends a string representation of this Segment to a StringBuffer. * * @param buf StringBuffer */ void toString(StringBuilder buf); /** * Returns the region of the source code which this Segment was created * from, if it was created by parsing. * * @return region of source code */ ParseRegion getRegion(); /** * Returns how this Segment is quoted. * * @return how this Segment is quoted */ Quoting getQuoting(); /** * Returns the name of this IdentifierSegment. * Returns {@code null} if this IdentifierSegment represents a key. * * @return name of this Segment */ String getName(); /** * Returns the key components, if this IdentifierSegment is a key. (That is, * if {@link #getQuoting()} returns * {@link Quoting#KEY}.) * * Returns null otherwise. * * @return Components of key, or null if this IdentifierSegment is not a key */ List getKeyParts(); } // End IdentifierSegment.java olap4j-1.0.1.500/src/org/olap4j/mdx/SelectNode.java0000644000175000017500000001735111707255000021334 0ustar drazzibdrazzib/* // $Id: SelectNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.Axis; import org.olap4j.type.Type; import java.io.PrintWriter; import java.io.StringWriter; import java.util.*; /** * Parse tree model for an MDX SELECT statement. * * @author jhyde * @version $Id: SelectNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public class SelectNode implements ParseTreeNode { private final ParseRegion region; private final List withList; private final List axisList; private final AxisNode filterAxis; private final List cellPropertyList; private ParseTreeNode from; /** * Creates a SelectNode. * * @param region Region of source code from which this node was created * @param withList List of members and sets defined in this query using * a WITH clause * @param axisList List of axes * @param from Contents of FROM clause (name of cube, or subquery) * @param filterAxis Filter axis * @param cellPropertyList List of properties */ public SelectNode( ParseRegion region, List withList, List axisList, ParseTreeNode from, AxisNode filterAxis, List cellPropertyList) { this.region = region; this.withList = withList; this.axisList = axisList; this.from = from; if (filterAxis == null) { filterAxis = new AxisNode( null, false, Axis.FILTER, Collections.emptyList(), null); } if (filterAxis.getAxis() != Axis.FILTER) { throw new IllegalArgumentException( "Filter axis must have type FILTER"); } this.filterAxis = filterAxis; this.cellPropertyList = cellPropertyList; } /** * Creates an empty SelectNode. * *

      The contents of the SelectNode, such as the axis list, can be * populated after construction. */ public SelectNode() { this( null, new ArrayList(), new ArrayList(), null, null, new ArrayList()); } public ParseRegion getRegion() { return region; } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public Type getType() { // not an expression, so has no type return null; } public String toString() { StringWriter sw = new StringWriter(); ParseTreeWriter pw = new ParseTreeWriter(sw); unparse(pw); return sw.toString(); } public void unparse(ParseTreeWriter writer) { final PrintWriter pw = writer.getPrintWriter(); if (!withList.isEmpty()) { pw.println("WITH"); for (ParseTreeNode with : withList) { with.unparse(writer); pw.println(); } } pw.print("SELECT"); int k = 0; for (AxisNode axis : axisList) { if (k++ > 0) { pw.println(","); } else { pw.println(); } axis.unparse(writer); } pw.println(); pw.print("FROM "); if (from instanceof SelectNode) { writer.indent(); pw.println("("); from.unparse(writer); pw.print(")"); writer.outdent(); } else { from.unparse(writer); } if (filterAxis.getExpression() != null) { pw.println(); pw.print("WHERE "); filterAxis.unparse(writer); } if (!cellPropertyList.isEmpty()) { pw.println(); pw.print("CELL PROPERTIES "); k = 0; for (IdentifierNode cellProperty : cellPropertyList) { if (k++ > 0) { pw.print(", "); } cellProperty.unparse(writer); } } } /** * Returns a list of calculated members and sets defined as the WITH * clause of this SelectNode. * *

      For example, the WITH clause of query * *

      * WITH MEMBER [Measures].[Foo] AS ' [Measures].[Unit Sales] * 2 ' * SET [Customers].[Top] AS ' TopCount([Customers].Members, 10) ' * SELECT FROM [Sales] *
      * * contains one {@link org.olap4j.mdx.WithMemberNode} and one * {@link org.olap4j.mdx.WithSetNode}. * *

      The returned list is mutable. * * @return list of calculated members and sets */ public List getWithList() { return withList; } /** * Returns a list of axes in this SelectNode. * *

      The returned list is mutable. * * @return list of axes */ public List getAxisList() { return axisList; } /** * Returns the filter axis defined by the WHERE clause of this SelectNode. * *

      Never returns {@code null}. If there is no WHERE clause, returns an * AxisNode for which {@link org.olap4j.mdx.AxisNode#getExpression()} * returns null. * *

      You can modify the filter expression by calling * {@link org.olap4j.mdx.AxisNode#getExpression()} on the filter AxisNode; * {@code null} means that there is no filter axis. * * @return filter axis */ public AxisNode getFilterAxis() { return filterAxis; } /** * Returns the node representing the FROM clause of this SELECT statement. * The node is typically an {@link IdentifierNode}, a {@link CubeNode} or * a {@link SelectNode}. * * @return FROM clause */ public ParseTreeNode getFrom() { return from; } /** * Sets the FROM clause of this SELECT statement. * *

      fromNode should typically by an * {@link org.olap4j.mdx.IdentifierNode} containing the cube name, or * a {@link org.olap4j.mdx.CubeNode} referencing an explicit * {@link org.olap4j.metadata.Cube} object. * * @param from FROM clause */ public void setFrom(ParseTreeNode from) { this.from = from; } /** * Returns a list of cell properties in this SelectNode. * *

      The returned list is mutable. * * @return list of cell properties */ public List getCellPropertyList() { return cellPropertyList; } public SelectNode deepCopy() { return new SelectNode( this.region, MdxUtil.deepCopyList(withList), MdxUtil.deepCopyList(axisList), this.from != null ? this.from.deepCopy() : null, this.filterAxis.deepCopy(), MdxUtil.deepCopyList(cellPropertyList)); } } // End SelectNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/CubeNode.java0000644000175000017500000000431111707255000020763 0ustar drazzibdrazzib/* // $Id: CubeNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; import org.olap4j.metadata.Cube; import org.olap4j.type.CubeType; import org.olap4j.type.Type; /** * Usage of a {@link org.olap4j.metadata.Cube} as an expression in an MDX * parse tree. * * @author jhyde * @version $Id: CubeNode.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jun 4, 2007 */ public class CubeNode implements ParseTreeNode { private final ParseRegion region; private final Cube cube; /** * Creates a CubeNode. * * @param region Region of source code * @param cube Cube */ public CubeNode( ParseRegion region, Cube cube) { this.region = region; this.cube = cube; } public ParseRegion getRegion() { return region; } /** * Returns the Cube used in this expression. * * @return cube used in this expression */ public Cube getCube() { return cube; } public T accept(ParseTreeVisitor visitor) { return visitor.visit(this); } public Type getType() { return new CubeType(cube); } public void unparse(ParseTreeWriter writer) { writer.getPrintWriter().print(cube.getUniqueName()); } public String toString() { return cube.getUniqueName(); } public CubeNode deepCopy() { // CubeNode is immutable return this; } } // End CubeNode.java olap4j-1.0.1.500/src/org/olap4j/mdx/Quoting.java0000644000175000017500000000326011707255000020727 0ustar drazzibdrazzib/* // $Id: Quoting.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.mdx; /** * Enumeration of styles by which the component of an identifier can be * quoted. * * @see org.olap4j.mdx.IdentifierSegment * * @version $Id: Quoting.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public enum Quoting { /** * Unquoted identifier, for example "Measures". */ UNQUOTED, /** * Quoted identifier, for example "[Measures]". */ QUOTED, /** * Identifier quoted with an ampersand and brackets to indicate a key * value, for example the second segment in "[Employees].&[89]". * *

      Such a segment has one or more sub-segments. Each segment is * either quoted or unquoted. For example, the second segment in * "[Employees].&[89]&[San Francisco]&CA&USA" has four sub-segments, * two quoted and two unquoted. */ KEY, } // End Quoting.java olap4j-1.0.1.500/src/org/olap4j/OlapStatement.java0000644000175000017500000000766011707255012021304 0ustar drazzibdrazzib/* // $Id: OlapStatement.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.mdx.SelectNode; import java.sql.SQLException; import java.sql.Statement; /** * Object used for statically executing an MDX statement and returning a * {@link CellSet}. * *

      An OlapStatement is generally created using * {@link OlapConnection#createStatement()}.

      * * @see PreparedOlapStatement * * @author jhyde * @version $Id: OlapStatement.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface OlapStatement extends Statement, OlapWrapper { /** * Retrieves the OlapConnection object * that produced this OlapStatement object. */ OlapConnection getConnection() throws SQLException; /** * Executes an OLAP statement. * * @param mdx MDX SELECT statement * * @return Cell set * * @throws OlapException if a database access error occurs, * this method is called on a closed OlapStatement, * the query times out (see {@link #setQueryTimeout(int)}) * or another thread cancels the statement (see {@link #cancel()}) */ CellSet executeOlapQuery(String mdx) throws OlapException; /** * Executes an OLAP statement expressed as a parse tree. * *

      Validates the parse tree before executing it. * * @param selectNode Parse tree of MDX SELECT statement * * @return Cell set * * @throws OlapException if a database access error occurs, * this method is called on a closed OlapStatement, * the query times out (see {@link #setQueryTimeout(int)}) * or another thread cancels the statement (see {@link #cancel()}) */ CellSet executeOlapQuery(SelectNode selectNode) throws OlapException; /** * Adds a listener to be notified of events to {@link CellSet}s created by * this statement. * *

      NOTE: You may wonder why this method belongs to the * {@link OlapStatement} class and not {@code CellSet}. If the method * belonged to {@code CellSet} there would be a window between creation and * registering a listener during which events might be lost, whereas * registering the listener with the statement ensures that the listener is * attached immediately that the cell set is opened. It follows that * registering a listener does not affect the cell set currently * open (if any), and that no events will be received if the statement * has no open cell sets. * * @param granularity Granularity of cell set events to listen for * * @param listener Listener to be notified of changes * * @throws OlapException if granularity is not one supported by this server, * per the * {@link OlapDatabaseMetaData#getSupportedCellSetListenerGranularities()} * method */ void addListener( CellSetListener.Granularity granularity, CellSetListener listener) throws OlapException; } // End OlapStatement.java olap4j-1.0.1.500/src/org/olap4j/Axis.java0000644000175000017500000001350011707255012017416 0ustar drazzibdrazzib/* // $Id: Axis.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import java.util.Locale; /** * Enumeration of axis types. * *

      The most commonly used values are * COLUMNS (the first axis of a 2-dimensional query), * ROWS (the second axis of a 2-dimensional query) and * FILTER (also known as the slicer axis, denoted by a * WHERE clause in an MDX statement). * * @author jhyde * @version $Id: Axis.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 23, 2006 */ public interface Axis { /** * Abbreviation for {@link org.olap4j.Axis.Standard#FILTER}. */ Standard FILTER = Standard.FILTER; /** * Abbreviation for {@link org.olap4j.Axis.Standard#COLUMNS}. */ Standard COLUMNS = Standard.COLUMNS; /** * Abbreviation for {@link org.olap4j.Axis.Standard#ROWS}. */ Standard ROWS = Standard.ROWS; /** * Abbreviation for {@link org.olap4j.Axis.Standard#PAGES}. */ Standard PAGES = Standard.PAGES; /** * Abbreviation for {@link org.olap4j.Axis.Standard#CHAPTERS}. */ Standard SECTIONS = Standard.SECTIONS; /** * Abbreviation for {@link org.olap4j.Axis.Standard#FILTER}. */ Standard CHAPTERS = Standard.CHAPTERS; /** * Returns the name of this axis, e.g. "COLUMNS", "FILTER", "AXIS(17)". * * @return Name of the axis */ String name(); /** * Returns whether this is the filter (slicer) axis. * * @return whether this is the filter axis */ boolean isFilter(); /** * Returns the ordinal which is to be used for retrieving this axis from * the {@link org.olap4j.CellSet#getAxes()}, or retrieving its * coordinate from {@link Cell#getCoordinateList()}. * *

      For example: *

        *
      • -1 {@link org.olap4j.Axis.Standard#FILTER FILTER}
      • *
      • 0 {@link org.olap4j.Axis.Standard#COLUMNS COLUMNS}
      • *
      • 1 {@link org.olap4j.Axis.Standard#ROWS ROWS}
      • *
      • 2 {@link org.olap4j.Axis.Standard#PAGES PAGES}
      • *
      • 3 {@link org.olap4j.Axis.Standard#CHAPTERS CHAPTERS}
      • *
      • 4 {@link org.olap4j.Axis.Standard#SECTIONS SECTIONS}
      • *
      • 5 {@link org.olap4j.Axis.Standard#SECTIONS SECTIONS}
      • *
      • 6 AXES(6)
      • *
      • 123 AXES(123)
      • *
      * * @return ordinal of this axis */ int axisOrdinal(); /** * Returns localized name for this Axis. * *

      Examples: "FILTER", "ROWS", "COLUMNS", "AXIS(10)". * * @param locale Locale for which to give the name * @return localized name for this Axis */ String getCaption(Locale locale); /** * Enumeration of standard, named axes descriptors. */ public enum Standard implements Axis { /** * Filter axis, also known as the slicer axis, and represented by the * WHERE clause of an MDX query. */ FILTER, /** COLUMNS axis, also known as X axis and AXIS(0). */ COLUMNS, /** ROWS axis, also known as Y axis and AXIS(1). */ ROWS, /** PAGES axis, also known as AXIS(2). */ PAGES, /** CHAPTERS axis, also known as AXIS(3). */ CHAPTERS, /** SECTIONS axis, also known as AXIS(4). */ SECTIONS; public int axisOrdinal() { return ordinal() - 1; } public boolean isFilter() { return this == FILTER; } public String getCaption(Locale locale) { // TODO: localize return name(); } } /** * Container class for various Axis factory methods. */ class Factory { private static final Standard[] STANDARD_VALUES = Standard.values(); /** * Returns the axis with a given ordinal. * *

      For example, {@code forOrdinal(0)} returns the COLUMNS axis; * {@code forOrdinal(-1)} returns the SLICER axis; * {@code forOrdinal(100)} returns AXIS(100). * * @param ordinal Axis ordinal * @return Axis whose ordinal is as given */ public static Axis forOrdinal(final int ordinal) { if (ordinal < -1) { throw new IllegalArgumentException( "Axis ordinal must be -1 or higher"); } if (ordinal + 1 < STANDARD_VALUES.length) { return STANDARD_VALUES[ordinal + 1]; } return new Axis() { public String toString() { return name(); } public String name() { return "AXIS(" + ordinal + ")"; } public boolean isFilter() { return false; } public int axisOrdinal() { return ordinal; } public String getCaption(Locale locale) { // TODO: localize return name(); } }; } } } // End Axis.java olap4j-1.0.1.500/src/org/olap4j/impl/0000755000175000017500000000000011632523246016615 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/impl/ConnectStringParser.java0000644000175000017500000002271011707255010023411 0ustar drazzibdrazzib/* // $Id: ConnectStringParser.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.*; /** * Parser for olap4j connect strings. * * @author jhyde * @version $Id: ConnectStringParser.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 12, 2007 */ // Copied from mondrian.olap.Util.ConnectStringParser public class ConnectStringParser { private final String s; private final int n; private int i; private final StringBuilder nameBuf; private final StringBuilder valueBuf; /** * Converts an OLE DB connect string into a {@link java.util.Map}. * *

      For example, "Provider=MSOLAP; DataSource=LOCALHOST;" * becomes the set of (key, value) pairs {("Provider","MSOLAP"), * ("DataSource", "LOCALHOST")}. Another example is * Provider='sqloledb';Data Source='MySqlServer';Initial * Catalog='Pubs';Integrated Security='SSPI';. * *

      This method implements as much as possible of the OLE DB connect string syntax * specification. * *

      The return value is a map which: *

        *
      • preserves the order in that the entries occurred;
      • *
      • is not case-sensitive when looking up properties
      • *
      * * @param s Connect string * * @return Map containing (name, value) pairs, stored in the order that * they occurred in the connect string */ public static Map parseConnectString(String s) { return new ConnectStringParser(s).parse(); } private ConnectStringParser(String s) { this.s = s; this.i = 0; this.n = s.length(); this.nameBuf = new StringBuilder(64); this.valueBuf = new StringBuilder(64); } private PropertyMap parse() { PropertyMap map = new PropertyMap(); while (i < n) { parsePair(map); } return map; } /** * Reads "name=value;" or "name=value". * * @param map Map to append value to */ private void parsePair(PropertyMap map) { String name = parseName(); if (name == null) { return; } String value; if (i >= n) { value = ""; } else if (s.charAt(i) == ';') { i++; value = ""; } else { value = parseValue(); } map.put(name, value); } /** * Reads "name=". Name can contain equals sign if equals sign is * doubled. * * @return Next name in the connect string being parsed, or null if there * is no further name */ private String parseName() { nameBuf.setLength(0); while (true) { char c = s.charAt(i); switch (c) { case '=': i++; if (i < n && (c = s.charAt(i)) == '=') { // doubled equals sign; take one of them, and carry on i++; nameBuf.append(c); break; } String name = nameBuf.toString(); name = name.trim(); return name; case ' ': if (nameBuf.length() == 0) { // ignore preceding spaces i++; if (i >= n) { // there is no name, e.g. trailing spaces after // semicolon, 'x=1; y=2; ' return null; } break; } else { // fall through } default: nameBuf.append(c); i++; if (i >= n) { return nameBuf.toString().trim(); } } } } /** * Reads "value;" or "value" * * @return next value from connect string being parsed */ private String parseValue() { char c; // skip over leading white space while ((c = s.charAt(i)) == ' ') { i++; if (i >= n) { return ""; } } if (c == '"' || c == '\'') { String value = parseQuoted(c); // skip over trailing white space while (i < n && (c = s.charAt(i)) == ' ') { i++; } if (i >= n) { return value; } else if (c == ';') { i++; return value; } else { throw new RuntimeException( "quoted value ended too soon, at position " + i + " in '" + s + "'"); } } else { String value; int semi = s.indexOf(';', i); if (semi >= 0) { value = s.substring(i, semi); i = semi + 1; } else { value = s.substring(i); i = n; } return value.trim(); } } /** * Reads a string quoted by a given character. Occurrences of the * quoting character must be doubled. For example, * parseQuoted('"') reads "a ""new"" string" * and returns a "new" string. * * @param q Quoting character (usually single or double quote) * @return quoted string */ private String parseQuoted(char q) { char c = s.charAt(i++); assert c == q; valueBuf.setLength(0); while (i < n) { c = s.charAt(i); if (c == q) { i++; if (i < n) { c = s.charAt(i); if (c == q) { valueBuf.append(c); i++; continue; } } return valueBuf.toString(); } else { valueBuf.append(c); i++; } } throw new RuntimeException( "Connect string '" + s + "' contains unterminated quoted value '" + valueBuf.toString() + "'"); } private static class PropertyMap extends LinkedHashMap { private final Map originalKeys = new HashMap(); private static final String PROVIDER = normalize("Provider"); public String get(Object key) { return super.get(normalize((String) key)); } public String remove(Object key) { return super.remove(normalize((String) key)); } public String put(String key, String value) { final String normalizedKey = normalize(key); if (normalizedKey.equals(PROVIDER) && containsKey(normalizedKey)) { // "Provider" is the sole property which does not override. // The first occurrence of "Provider" is the one which is used. return null; } originalKeys.put(normalizedKey, key); return super.put(normalizedKey, value); } public boolean containsKey(Object key) { return super.containsKey(normalize((String) key)); } private static String normalize(String key) { return key.toUpperCase(); } public String toString() { StringBuilder sb = new StringBuilder(64); int i = 0; for (Map.Entry entry : entrySet()) { if (i++ > 0) { sb.append("; "); } final String key = entry.getKey(); final String originalKey = originalKeys.get(key); sb.append(originalKey); sb.append('='); final String value = entry.getValue(); if (value == null) { sb.append("'null'"); } else { /* * Quote a property value if is has a semi colon in it * 'xxx;yyy'; */ if (value.indexOf(';') >= 0 && value.charAt(0) != '\'') { sb.append("'"); } sb.append(value); if (value.indexOf(';') >= 0 && value.charAt(value.length() - 1) != '\'') { sb.append("'"); } } } return sb.toString(); } } } // End ConnectStringParser.java olap4j-1.0.1.500/src/org/olap4j/impl/Base64.java0000644000175000017500000014663011707255010020510 0ustar drazzibdrazzib/* // $Id: Base64.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; /** * Encodes and decodes to and from Base64 notation. * *

      * Change Log: *

      *
        *
      • v2.1 - Cleaned up javadoc comments and unused variables and methods. Added * some convenience methods for reading and writing to and from files.
      • *
      • v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems * with other encodings (like EBCDIC).
      • *
      • v2.0.1 - Fixed an error when decoding a single byte, that is, when the * encoded data was a single byte.
      • *
      • v2.0 - I got rid of methods that used booleans to set options. * Now everything is more consolidated and cleaner. The code now detects * when data that's being decoded is gzip-compressed and will decompress it * automatically. Generally things are cleaner. You'll probably have to * change some method calls that you were making to support the new * options format (ints that you "OR" together).
      • *
      • v1.5.1 - Fixed bug when decompressing and decoding to a * byte[] using decode( String s, boolean gzipCompressed ). * Added the ability to "suspend" encoding in the Output Stream so * you can turn on and off the encoding if you need to embed base64 * data in an otherwise "normal" stream (like an XML file).
      • *
      • v1.5 - Output stream pases on flush() command but doesn't do anything itself. * This helps when using GZIP streams. * Added the ability to GZip-compress objects before encoding them.
      • *
      • v1.4 - Added helper methods to read/write files.
      • *
      • v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.
      • *
      • v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream * where last buffer being read, if not completely full, was not returned.
      • *
      • v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.
      • *
      • v1.3.3 - Fixed I/O streams which were totally messed up.
      • *
      * *

      * I am placing this code in the Public Domain. Do with it as you will. * This software comes with no guarantees or warranties but with * plenty of well-wishing instead! * Please visit http://iharder.net/base64 * periodically to check for updates or to contribute improvements. *

      * * @author Robert Harder * @author rob@iharder.net * @version 2.1 */ @SuppressWarnings({"EmptyCatchBlock", "JavaDoc"}) public class Base64 { /* ******** P U B L I C F I E L D S ******** */ /** No options specified. Value is zero. */ public final static int NO_OPTIONS = 0; /** Specify encoding. */ public final static int ENCODE = 1; /** Specify decoding. */ public final static int DECODE = 0; /** Specify that data should be gzip-compressed. */ public final static int GZIP = 2; /** Don't break lines when encoding (violates strict Base64 specification) */ public final static int DONT_BREAK_LINES = 8; /* ******** P R I V A T E F I E L D S ******** */ /** Maximum line length (76) of Base64 output. */ private final static int MAX_LINE_LENGTH = 76; /** The equals sign (=) as a byte. */ private final static byte EQUALS_SIGN = (byte)'='; /** The new line character (\n) as a byte. */ private final static byte NEW_LINE = (byte)'\n'; /** Preferred encoding. */ private final static String PREFERRED_ENCODING = "UTF-8"; /** The 64 valid Base64 values. */ private final static byte[] ALPHABET; private final static byte[] _NATIVE_ALPHABET = /* May be something funny like EBCDIC */ { (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' }; /** Determine which ALPHABET to use. */ static { byte[] __bytes; try { __bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes( PREFERRED_ENCODING ); } // end try catch (java.io.UnsupportedEncodingException use) { __bytes = _NATIVE_ALPHABET; // Fall back to native encoding } // end catch ALPHABET = __bytes; } // end static /** * Translates a Base64 value to either its 6-bit reconstruction value * or a negative number indicating some other meaning. **/ private final static byte[] DECODABET = { -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 -5,-5, // Whitespace: Tab and Linefeed -9,-9, // Decimal 11 - 12 -5, // Whitespace: Carriage Return -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 -9,-9,-9,-9,-9, // Decimal 27 - 31 -5, // Whitespace: Space -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 62, // Plus sign at decimal 43 -9,-9,-9, // Decimal 44 - 46 63, // Slash at decimal 47 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine -9,-9,-9, // Decimal 58 - 60 -1, // Equals sign at decimal 61 -9,-9,-9, // Decimal 62 - 64 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' -9,-9,-9,-9 // Decimal 123 - 126 /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ }; // I think I end up not using the BAD_ENCODING indicator. //private final static byte BAD_ENCODING = -9; // Indicates error in encoding private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding /** Defeats instantiation. */ private Base64(){} /* ******** E N C O D I N G M E T H O D S ******** */ /** * Encodes up to the first three bytes of array threeBytes * and returns a four-byte array in Base64 notation. * The actual number of significant bytes in your array is * given by numSigBytes. * The array threeBytes needs only be as big as * numSigBytes. * Code can reuse a byte array by passing a four-byte array as b4. * * @param b4 A reusable byte array to reduce array instantiation * @param threeBytes the array to convert * @param numSigBytes the number of significant bytes in your array * @return four byte array in Base64 notation. * @since 1.5.1 */ private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes ) { encode3to4( threeBytes, 0, numSigBytes, b4, 0 ); return b4; } // end encode3to4 /** * Encodes up to three bytes of the array source * and writes the resulting four Base64 bytes to destination. * The source and destination arrays can be manipulated * anywhere along their length by specifying * srcOffset and destOffset. * This method does not check to make sure your arrays * are large enough to accomodate srcOffset + 3 for * the source array or destOffset + 4 for * the destination array. * The actual number of significant bytes in your array is * given by numSigBytes. * * @param source the array to convert * @param srcOffset the index where conversion begins * @param numSigBytes the number of significant bytes in your array * @param destination the array to hold the conversion * @param destOffset the index where output will be put * @return the destination array * @since 1.3 */ private static byte[] encode3to4( byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset ) { // 1 2 3 // 01234567890123456789012345678901 Bit position // --------000000001111111122222222 Array position from threeBytes // --------| || || || | Six bit groups to index ALPHABET // >>18 >>12 >> 6 >> 0 Right shift necessary // 0x3f 0x3f 0x3f Additional AND // Create buffer with zero-padding if there are only one or two // significant bytes passed in the array. // We have to shift left 24 in order to flush out the 1's that appear // when Java treats a value as negative that is cast from a byte to an int. int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 ) | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 ) | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 ); switch( numSigBytes ) { case 3: destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ]; return destination; case 2: destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; destination[ destOffset + 3 ] = EQUALS_SIGN; return destination; case 1: destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; destination[ destOffset + 2 ] = EQUALS_SIGN; destination[ destOffset + 3 ] = EQUALS_SIGN; return destination; default: return destination; } // end switch } // end encode3to4 /** * Serializes an object and returns the Base64-encoded * version of that serialized object. If the object * cannot be serialized or there is another error, * the method will return null. * The object is not GZip-compressed before being encoded. * * @param serializableObject The object to encode * @return The Base64-encoded object * @since 1.4 */ public static String encodeObject( java.io.Serializable serializableObject ) { return encodeObject( serializableObject, NO_OPTIONS ); } // end encodeObject /** * Serializes an object and returns the Base64-encoded * version of that serialized object. If the object * cannot be serialized or there is another error, * the method will return null. *

      * Valid options:

           *   GZIP: gzip-compresses object before encoding it.
           *   DONT_BREAK_LINES: don't break lines at 76 characters
           *     Note: Technically, this makes your encoding non-compliant.
           * 
      *

      * Example: encodeObject( myObj, Base64.GZIP ) or *

      * Example: encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES ) * * @param serializableObject The object to encode * @param options Specified options * @return The Base64-encoded object * @see Base64#GZIP * @see Base64#DONT_BREAK_LINES * @since 2.0 */ public static String encodeObject( java.io.Serializable serializableObject, int options ) { // Streams java.io.ByteArrayOutputStream baos = null; java.io.OutputStream b64os = null; java.io.ObjectOutputStream oos = null; java.util.zip.GZIPOutputStream gzos = null; // Isolate options int gzip = (options & GZIP); int dontBreakLines = (options & DONT_BREAK_LINES); try { // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); b64os = new Base64.OutputStream( baos, ENCODE | dontBreakLines ); // GZip? if( gzip == GZIP ) { gzos = new java.util.zip.GZIPOutputStream( b64os ); oos = new java.io.ObjectOutputStream( gzos ); } // end if: gzip else oos = new java.io.ObjectOutputStream( b64os ); oos.writeObject( serializableObject ); } // end try catch( java.io.IOException e ) { e.printStackTrace(); return null; } // end catch finally { try{ oos.close(); } catch( Exception e ){} try{ gzos.close(); } catch( Exception e ){} try{ b64os.close(); } catch( Exception e ){} try{ baos.close(); } catch( Exception e ){} } // end finally // Return value according to relevant encoding. try { return new String( baos.toByteArray(), PREFERRED_ENCODING ); } // end try catch (java.io.UnsupportedEncodingException uue) { return new String( baos.toByteArray() ); } // end catch } // end encode /** * Encodes a byte array into Base64 notation. * Does not GZip-compress data. * * @param source The data to convert * @since 1.4 */ public static String encodeBytes( byte[] source ) { return encodeBytes( source, 0, source.length, NO_OPTIONS ); } // end encodeBytes /** * Encodes a byte array into Base64 notation. *

      * Valid options:

           *   GZIP: gzip-compresses object before encoding it.
           *   DONT_BREAK_LINES: don't break lines at 76 characters
           *     Note: Technically, this makes your encoding non-compliant.
           * 
      *

      * Example: encodeBytes( myData, Base64.GZIP ) or *

      * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES ) * * * @param source The data to convert * @param options Specified options * @see Base64#GZIP * @see Base64#DONT_BREAK_LINES * @since 2.0 */ public static String encodeBytes( byte[] source, int options ) { return encodeBytes( source, 0, source.length, options ); } // end encodeBytes /** * Encodes a byte array into Base64 notation. * Does not GZip-compress data. * * @param source The data to convert * @param off Offset in array where conversion should begin * @param len Length of data to convert * @since 1.4 */ public static String encodeBytes( byte[] source, int off, int len ) { return encodeBytes( source, off, len, NO_OPTIONS ); } // end encodeBytes /** * Encodes a byte array into Base64 notation. *

      * Valid options:

           *   GZIP: gzip-compresses object before encoding it.
           *   DONT_BREAK_LINES: don't break lines at 76 characters
           *     Note: Technically, this makes your encoding non-compliant.
           * 
      *

      * Example: encodeBytes( myData, Base64.GZIP ) or *

      * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES ) * * * @param source The data to convert * @param off Offset in array where conversion should begin * @param len Length of data to convert * @param options Specified options * @see Base64#GZIP * @see Base64#DONT_BREAK_LINES * @since 2.0 */ public static String encodeBytes( byte[] source, int off, int len, int options ) { // Isolate options int dontBreakLines = ( options & DONT_BREAK_LINES ); int gzip = ( options & GZIP ); // Compress? if( gzip == GZIP ) { java.io.ByteArrayOutputStream baos = null; java.util.zip.GZIPOutputStream gzos = null; Base64.OutputStream b64os = null; try { // GZip -> Base64 -> ByteArray baos = new java.io.ByteArrayOutputStream(); b64os = new Base64.OutputStream( baos, ENCODE | dontBreakLines ); gzos = new java.util.zip.GZIPOutputStream( b64os ); gzos.write( source, off, len ); gzos.close(); } // end try catch( java.io.IOException e ) { e.printStackTrace(); return null; } // end catch finally { try{ gzos.close(); } catch( Exception e ){} try{ b64os.close(); } catch( Exception e ){} try{ baos.close(); } catch( Exception e ){} } // end finally // Return value according to relevant encoding. try { return new String( baos.toByteArray(), PREFERRED_ENCODING ); } // end try catch (java.io.UnsupportedEncodingException uue) { return new String( baos.toByteArray() ); } // end catch } // end if: compress // Else, don't compress. Better not to use streams at all then. else { // Convert option to boolean in way that code likes it. boolean breakLines = dontBreakLines == 0; int len43 = len * 4 / 3; byte[] outBuff = new byte[ ( len43 ) // Main 4:3 + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines int d = 0; int e = 0; int len2 = len - 2; int lineLength = 0; for( ; d < len2; d+=3, e+=4 ) { encode3to4( source, d+off, 3, outBuff, e ); lineLength += 4; if( breakLines && lineLength == MAX_LINE_LENGTH ) { outBuff[e+4] = NEW_LINE; e++; lineLength = 0; } // end if: end of line } // en dfor: each piece of array if( d < len ) { encode3to4( source, d+off, len - d, outBuff, e ); e += 4; } // end if: some padding needed // Return value according to relevant encoding. try { return new String( outBuff, 0, e, PREFERRED_ENCODING ); } // end try catch (java.io.UnsupportedEncodingException uue) { return new String( outBuff, 0, e ); } // end catch } // end else: don't compress } // end encodeBytes /* ******** D E C O D I N G M E T H O D S ******** */ /** * Decodes four bytes from array source * and writes the resulting bytes (up to three of them) * to destination. * The source and destination arrays can be manipulated * anywhere along their length by specifying * srcOffset and destOffset. * This method does not check to make sure your arrays * are large enough to accomodate srcOffset + 4 for * the source array or destOffset + 3 for * the destination array. * This method returns the actual number of bytes that * were converted from the Base64 encoding. * * * @param source the array to convert * @param srcOffset the index where conversion begins * @param destination the array to hold the conversion * @param destOffset the index where output will be put * @return the number of decoded bytes converted * @since 1.3 */ private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset ) { // Example: Dk== if( source[ srcOffset + 2] == EQUALS_SIGN ) { // Two ways to do the same thing. Don't know which way I like best. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); destination[ destOffset ] = (byte)( outBuff >>> 16 ); return 1; } // Example: DkL= else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) { // Two ways to do the same thing. Don't know which way I like best. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); destination[ destOffset ] = (byte)( outBuff >>> 16 ); destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); return 2; } // Example: DkLE else { try{ // Two ways to do the same thing. Don't know which way I like best. //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); destination[ destOffset ] = (byte)( outBuff >> 16 ); destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); destination[ destOffset + 2 ] = (byte)( outBuff ); return 3; }catch( Exception e){ System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) ); System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) ); System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) ); System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) ); return -1; } //e nd catch } } // end decodeToBytes /** * Very low-level access to decoding ASCII characters in * the form of a byte array. Does not support automatically * gunzipping or any other "fancy" features. * * @param source The Base64 encoded data * @param off The offset of where to begin decoding * @param len The length of characters to decode * @return decoded data * @since 1.3 */ public static byte[] decode( byte[] source, int off, int len ) { int len34 = len * 3 / 4; byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output int outBuffPosn = 0; byte[] b4 = new byte[4]; int b4Posn = 0; int i = 0; byte sbiCrop = 0; byte sbiDecode = 0; for( i = off; i < off+len; i++ ) { sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits sbiDecode = DECODABET[ sbiCrop ]; if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better { if( sbiDecode >= EQUALS_SIGN_ENC ) { b4[ b4Posn++ ] = sbiCrop; if( b4Posn > 3 ) { outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn ); b4Posn = 0; // If that was the equals sign, break out of 'for' loop if( sbiCrop == EQUALS_SIGN ) break; } // end if: quartet built } // end if: equals sign or better } // end if: white space, equals sign or better else { System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); return null; } // end else: } // each input character byte[] out = new byte[ outBuffPosn ]; System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); return out; } // end decode /** * Decodes data from Base64 notation, automatically * detecting gzip-compressed data and decompressing it. * * @param s the string to decode * @return the decoded data * @since 1.4 */ public static byte[] decode( String s ) { byte[] bytes; try { bytes = s.getBytes( PREFERRED_ENCODING ); } // end try catch( java.io.UnsupportedEncodingException uee ) { bytes = s.getBytes(); } // end catch // // Decode bytes = decode( bytes, 0, bytes.length ); // Check to see if it's gzip-compressed // GZIP Magic Two-Byte Number: 0x8b1f (35615) if( bytes != null && bytes.length >= 4 ) { int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) { java.io.ByteArrayInputStream bais = null; java.util.zip.GZIPInputStream gzis = null; java.io.ByteArrayOutputStream baos = null; byte[] buffer = new byte[2048]; int length = 0; try { baos = new java.io.ByteArrayOutputStream(); bais = new java.io.ByteArrayInputStream( bytes ); gzis = new java.util.zip.GZIPInputStream( bais ); while( ( length = gzis.read( buffer ) ) >= 0 ) { baos.write(buffer,0,length); } // end while: reading input // No error? Get new bytes. bytes = baos.toByteArray(); } // end try catch( java.io.IOException e ) { // Just return originally-decoded bytes } // end catch finally { try{ baos.close(); } catch( Exception e ){} try{ gzis.close(); } catch( Exception e ){} try{ bais.close(); } catch( Exception e ){} } // end finally } // end if: gzipped } // end if: bytes.length >= 2 return bytes; } // end decode /** * Attempts to decode Base64 data and deserialize a Java * Object within. Returns null if there was an error. * * @param encodedObject The Base64 data to decode * @return The decoded and deserialized object * @since 1.5 */ public static Object decodeToObject( String encodedObject ) { // Decode and gunzip if necessary byte[] objBytes = decode( encodedObject ); java.io.ByteArrayInputStream bais = null; java.io.ObjectInputStream ois = null; Object obj = null; try { bais = new java.io.ByteArrayInputStream( objBytes ); ois = new java.io.ObjectInputStream( bais ); obj = ois.readObject(); } // end try catch( java.io.IOException e ) { e.printStackTrace(); obj = null; } // end catch catch( ClassNotFoundException e ) { e.printStackTrace(); obj = null; } // end catch finally { try{ bais.close(); } catch( Exception e ){} try{ ois.close(); } catch( Exception e ){} } // end finally return obj; } // end decodeObject /** * Convenience method for encoding data to a file. * * @param dataToEncode byte array of data to encode in base64 form * @param filename Filename for saving encoded data * @return true if successful, false otherwise * * @since 2.1 */ public static boolean encodeToFile( byte[] dataToEncode, String filename ) { boolean success = false; Base64.OutputStream bos = null; try { bos = new Base64.OutputStream( new java.io.FileOutputStream( filename ), Base64.ENCODE ); bos.write( dataToEncode ); success = true; } // end try catch( java.io.IOException e ) { success = false; } // end catch: IOException finally { try{ bos.close(); } catch( Exception e ){} } // end finally return success; } // end encodeToFile /** * Convenience method for decoding data to a file. * * @param dataToDecode Base64-encoded data as a string * @param filename Filename for saving decoded data * @return true if successful, false otherwise * * @since 2.1 */ public static boolean decodeToFile( String dataToDecode, String filename ) { boolean success = false; Base64.OutputStream bos = null; try { bos = new Base64.OutputStream( new java.io.FileOutputStream( filename ), Base64.DECODE ); bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) ); success = true; } // end try catch( java.io.IOException e ) { success = false; } // end catch: IOException finally { try{ bos.close(); } catch( Exception e ){} } // end finally return success; } // end decodeToFile /** * Convenience method for reading a base64-encoded * file and decoding it. * * @param filename Filename for reading encoded data * @return decoded byte array or null if unsuccessful * * @since 2.1 */ public static byte[] decodeFromFile( String filename ) { byte[] decodedData = null; Base64.InputStream bis = null; try { // Set up some useful variables java.io.File file = new java.io.File( filename ); byte[] buffer = null; int length = 0; int numBytes = 0; // Check for size of file if( file.length() > Integer.MAX_VALUE ) { System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." ); return null; } // end if: file too big for int index buffer = new byte[ (int)file.length() ]; // Open a stream bis = new Base64.InputStream( new java.io.BufferedInputStream( new java.io.FileInputStream( file ) ), Base64.DECODE ); // Read until done while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) length += numBytes; // Save in a variable to return decodedData = new byte[ length ]; System.arraycopy( buffer, 0, decodedData, 0, length ); } // end try catch( java.io.IOException e ) { System.err.println( "Error decoding from file " + filename ); } // end catch: IOException finally { try{ bis.close(); } catch( Exception e) {} } // end finally return decodedData; } // end decodeFromFile /** * Convenience method for reading a binary file * and base64-encoding it. * * @param filename Filename for reading binary data * @return base64-encoded string or null if unsuccessful * * @since 2.1 */ public static String encodeFromFile( String filename ) { String encodedData = null; Base64.InputStream bis = null; try { // Set up some useful variables java.io.File file = new java.io.File( filename ); byte[] buffer = new byte[ (int)(file.length() * 1.4) ]; int length = 0; int numBytes = 0; // Open a stream bis = new Base64.InputStream( new java.io.BufferedInputStream( new java.io.FileInputStream( file ) ), Base64.ENCODE ); // Read until done while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) length += numBytes; // Save in a variable to return encodedData = new String( buffer, 0, length, PREFERRED_ENCODING ); } // end try catch( java.io.IOException e ) { System.err.println( "Error encoding from file " + filename ); } // end catch: IOException finally { try{ bis.close(); } catch( Exception e) {} } // end finally return encodedData; } // end encodeFromFile /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ /** * A {@link Base64.InputStream} will read data from another * java.io.InputStream, given in the constructor, * and encode/decode to/from Base64 notation on the fly. * * @see Base64 * @since 1.3 */ public static class InputStream extends java.io.FilterInputStream { private boolean encode; // Encoding or decoding private int position; // Current position in the buffer private byte[] buffer; // Small buffer holding converted data private int bufferLength; // Length of buffer (3 or 4) private int numSigBytes; // Number of meaningful bytes in the buffer private int lineLength; private boolean breakLines; // Break lines at less than 80 characters /** * Constructs a {@link Base64.InputStream} in DECODE mode. * * @param in the java.io.InputStream from which to read data. * @since 1.3 */ public InputStream( java.io.InputStream in ) { this( in, DECODE ); } // end constructor /** * Constructs a {@link Base64.InputStream} in * either ENCODE or DECODE mode. *

      * Valid options:

               *   ENCODE or DECODE: Encode or Decode as data is read.
               *   DONT_BREAK_LINES: don't break lines at 76 characters
               *     (only meaningful when encoding)
               *     Note: Technically, this makes your encoding non-compliant.
               * 
      *

      * Example: new Base64.InputStream( in, Base64.DECODE ) * * * @param in the java.io.InputStream from which to read data. * @param options Specified options * @see Base64#ENCODE * @see Base64#DECODE * @see Base64#DONT_BREAK_LINES * @since 2.0 */ public InputStream( java.io.InputStream in, int options ) { super( in ); this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; this.encode = (options & ENCODE) == ENCODE; this.bufferLength = encode ? 4 : 3; this.buffer = new byte[ bufferLength ]; this.position = -1; this.lineLength = 0; } // end constructor /** * Reads enough of the input stream to convert * to/from Base64 and returns the next byte. * * @return next byte * @since 1.3 */ public int read() throws java.io.IOException { // Do we need to get data? if( position < 0 ) { if( encode ) { byte[] b3 = new byte[3]; int numBinaryBytes = 0; for( int i = 0; i < 3; i++ ) { try { int b = in.read(); // If end of stream, b is -1. if( b >= 0 ) { b3[i] = (byte)b; numBinaryBytes++; } // end if: not end of stream } // end try: read catch( java.io.IOException e ) { // Only a problem if we got no data at all. if( i == 0 ) throw e; } // end catch } // end for: each needed input byte if( numBinaryBytes > 0 ) { encode3to4( b3, 0, numBinaryBytes, buffer, 0 ); position = 0; numSigBytes = 4; } // end if: got data else { return -1; } // end else } // end if: encoding // Else decoding else { byte[] b4 = new byte[4]; int i = 0; for( i = 0; i < 4; i++ ) { // Read four "meaningful" bytes: int b = 0; do{ b = in.read(); } while( b >= 0 && DECODABET[ b & 0x7f ] <= WHITE_SPACE_ENC ); if( b < 0 ) break; // Reads a -1 if end of stream b4[i] = (byte)b; } // end for: each needed input byte if( i == 4 ) { numSigBytes = decode4to3( b4, 0, buffer, 0 ); position = 0; } // end if: got four characters else if( i == 0 ){ return -1; } // end else if: also padded correctly else { // Must have broken out from above. throw new java.io.IOException( "Improperly padded Base64 input." ); } // end } // end else: decode } // end else: get data // Got data? if( position >= 0 ) { // End of relevant data? if( /*!encode &&*/ position >= numSigBytes ) return -1; if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) { lineLength = 0; return '\n'; } // end if else { lineLength++; // This isn't important when decoding // but throwing an extra "if" seems // just as wasteful. int b = buffer[ position++ ]; if( position >= bufferLength ) position = -1; return b & 0xFF; // This is how you "cast" a byte that's // intended to be unsigned. } // end else } // end if: position >= 0 // Else error else { // When JDK1.4 is more accepted, use an assertion here. throw new java.io.IOException( "Error in Base64 code reading stream." ); } // end else } // end read /** * Calls {@link #read()} repeatedly until the end of stream * is reached or len bytes are read. * Returns number of bytes read into array or -1 if * end of stream is encountered. * * @param dest array to hold values * @param off offset for array * @param len max number of bytes to read into array * @return bytes read into array or -1 if end of stream is encountered. * @since 1.3 */ public int read( byte[] dest, int off, int len ) throws java.io.IOException { int i; int b; for( i = 0; i < len; i++ ) { b = read(); //if( b < 0 && i == 0 ) // return -1; if( b >= 0 ) dest[off + i] = (byte)b; else if( i == 0 ) return -1; else break; // Out of 'for' loop } // end for: each byte read return i; } // end read } // end inner class InputStream /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */ /** * A {@link Base64.OutputStream} will write data to another * java.io.OutputStream, given in the constructor, * and encode/decode to/from Base64 notation on the fly. * * @see Base64 * @since 1.3 */ public static class OutputStream extends java.io.FilterOutputStream { private boolean encode; private int position; private byte[] buffer; private int bufferLength; private int lineLength; private boolean breakLines; private byte[] b4; // Scratch used in a few places private boolean suspendEncoding; /** * Constructs a {@link Base64.OutputStream} in ENCODE mode. * * @param out the java.io.OutputStream to which data will be written. * @since 1.3 */ public OutputStream( java.io.OutputStream out ) { this( out, ENCODE ); } // end constructor /** * Constructs a {@link Base64.OutputStream} in * either ENCODE or DECODE mode. *

      * Valid options:

               *   ENCODE or DECODE: Encode or Decode as data is read.
               *   DONT_BREAK_LINES: don't break lines at 76 characters
               *     (only meaningful when encoding)
               *     Note: Technically, this makes your encoding non-compliant.
               * 
      *

      * Example: new Base64.OutputStream( out, Base64.ENCODE ) * * @param out the java.io.OutputStream to which data will be written. * @param options Specified options. * @see Base64#ENCODE * @see Base64#DECODE * @see Base64#DONT_BREAK_LINES * @since 1.3 */ public OutputStream( java.io.OutputStream out, int options ) { super( out ); this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; this.encode = (options & ENCODE) == ENCODE; this.bufferLength = encode ? 3 : 4; this.buffer = new byte[ bufferLength ]; this.position = 0; this.lineLength = 0; this.suspendEncoding = false; this.b4 = new byte[4]; } // end constructor /** * Writes the byte to the output stream after * converting to/from Base64 notation. * When encoding, bytes are buffered three * at a time before the output stream actually * gets a write() call. * When decoding, bytes are buffered four * at a time. * * @param theByte the byte to write * @since 1.3 */ public void write(int theByte) throws java.io.IOException { // Encoding suspended? if( suspendEncoding ) { super.out.write( theByte ); return; } // end if: supsended // Encode? if( encode ) { buffer[ position++ ] = (byte)theByte; if( position >= bufferLength ) // Enough to encode. { out.write( encode3to4( b4, buffer, bufferLength ) ); lineLength += 4; if( breakLines && lineLength >= MAX_LINE_LENGTH ) { out.write( NEW_LINE ); lineLength = 0; } // end if: end of line position = 0; } // end if: enough to output } // end if: encoding // Else, Decoding else { // Meaningful Base64 character? if( DECODABET[ theByte & 0x7f ] > WHITE_SPACE_ENC ) { buffer[ position++ ] = (byte)theByte; if( position >= bufferLength ) // Enough to output. { int len = Base64.decode4to3( buffer, 0, b4, 0 ); out.write( b4, 0, len ); //out.write( Base64.decode4to3( buffer ) ); position = 0; } // end if: enough to output } // end if: meaningful base64 character else if( DECODABET[ theByte & 0x7f ] != WHITE_SPACE_ENC ) { throw new java.io.IOException( "Invalid character in Base64 data." ); } // end else: not white space either } // end else: decoding } // end write /** * Calls {@link #write(int)} repeatedly until len * bytes are written. * * @param theBytes array from which to read bytes * @param off offset for array * @param len max number of bytes to read into array * @since 1.3 */ public void write( byte[] theBytes, int off, int len ) throws java.io.IOException { // Encoding suspended? if( suspendEncoding ) { super.out.write( theBytes, off, len ); return; } // end if: supsended for( int i = 0; i < len; i++ ) { write( theBytes[ off + i ] ); } // end for: each byte written } // end write /** * Method added by PHIL. [Thanks, PHIL. -Rob] * This pads the buffer without closing the stream. */ public void flushBase64() throws java.io.IOException { if( position > 0 ) { if( encode ) { out.write( encode3to4( b4, buffer, position ) ); position = 0; } // end if: encoding else { throw new java.io.IOException( "Base64 input not properly padded." ); } // end else: decoding } // end if: buffer partially full } // end flush /** * Flushes and closes (I think, in the superclass) the stream. * * @since 1.3 */ public void close() throws java.io.IOException { // 1. Ensure that pending characters are written flushBase64(); // 2. Actually close the stream // Base class both flushes and closes. super.close(); buffer = null; out = null; } // end close /** * Suspends encoding of the stream. * May be helpful if you need to embed a piece of * base640-encoded data in a stream. * * @since 1.5.1 */ public void suspendEncoding() throws java.io.IOException { flushBase64(); this.suspendEncoding = true; } // end suspendEncoding /** * Resumes encoding of the stream. * May be helpful if you need to embed a piece of * base640-encoded data in a stream. * * @since 1.5.1 */ public void resumeEncoding() { this.suspendEncoding = false; } // end resumeEncoding } // end inner class OutputStream } // end class Base64 // End Base64.java olap4j-1.0.1.500/src/org/olap4j/impl/package.html0000644000175000017500000000035311421322454021071 0ustar drazzibdrazzib Contains miscellaneous classes used by the olap4j API and drivers implementing the API.

      The classes in this package are not part of the public olap4j API and are subject to change without notice.

      olap4j-1.0.1.500/src/org/olap4j/impl/Olap4jUtilCompatibleJdk15.java0000644000175000017500000000371011707255010024241 0ustar drazzibdrazzib/* // $Id: Olap4jUtilCompatibleJdk15.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.EnumSet; import java.util.Set; import java.util.regex.Pattern; /** * Implementation of {@link Olap4jUtilCompatible} which runs in * JDK 1.5 and later. * *

      Prior to JDK 1.5, this class should never be loaded. Applications should * instantiate this class via {@link Class#forName(String)} or better, use * methods in {@link Olap4jUtil}, and not instantiate it at all. * * @author jhyde * @version $Id: Olap4jUtilCompatibleJdk15.java 482 2012-01-05 23:27:27Z jhyde $ * @since Feb 5, 2007 */ public class Olap4jUtilCompatibleJdk15 implements Olap4jUtilCompatible { public final String quotePattern(String s) { return Pattern.quote(s); } public final > Set enumSetOf(E first, E... rest) { return EnumSet.of(first, rest); } public final > Set enumSetNoneOf(Class elementType) { return EnumSet.noneOf(elementType); } public final > Set enumSetAllOf(Class elementType) { return EnumSet.allOf(elementType); } } // End Olap4jUtilCompatibleJdk15.java olap4j-1.0.1.500/src/org/olap4j/impl/CoordinateIterator.java0000644000175000017500000000774411707255010023267 0ustar drazzibdrazzib/* // $Id: CoordinateIterator.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.Iterator; /** * Iterator over the coordinates of a hyper-rectangle. * *

      For example, {@code new CoordinateIterator(new int[] {3, 2})} generates * the pairs {@code {0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1} }. * * @author jhyde * @version $Id: CoordinateIterator.java 482 2012-01-05 23:27:27Z jhyde $ * @since Apr 7, 2009 */ public class CoordinateIterator implements Iterator { private final int[] dimensions; private final boolean littleEndian; private final int[] current; private boolean hasNext; /** * Creates a big-endian coordinate iterator. * * @param dimensions Array containing the number of elements of each * coordinate axis */ public CoordinateIterator(int[] dimensions) { this(dimensions, false); } /** * Creates a coordinate iterator. * * @param dimensions Array containing the number of elements of each * @param littleEndian Whether coordinate 0 is the least significant * (and fastest changing) coordinate */ public CoordinateIterator(int[] dimensions, boolean littleEndian) { this.dimensions = dimensions; this.littleEndian = littleEndian; this.current = new int[dimensions.length]; this.hasNext = true; for (int dimension : dimensions) { if (dimension <= 0) { // an axis is empty. no results will be produced hasNext = false; break; } } } /** * Creates an {@link Iterable} that yields a * {@link org.olap4j.impl.CoordinateIterator}. * *

      Useful in a foreach loop, for example: * *

      int[] dimensions; * for (int[] coords : CoordinateIterator.iterate(dimensions)) { * foo(coords); * } *
      * * @param dimensions Array containing the number of elements of each * coordinate axis * * @return Iterable */ public static Iterable iterate(final int[] dimensions) { return new Iterable() { public Iterator iterator() { return new CoordinateIterator(dimensions, true); } }; } public boolean hasNext() { return hasNext; } public int[] next() { final int[] result = current.clone(); moveToNext(); return result; } private void moveToNext() { if (littleEndian) { for (int offset = 0; offset < dimensions.length; ++offset) { int k = ++current[offset]; if (k < dimensions[offset]) { return; } current[offset] = 0; } } else { for (int offset = dimensions.length - 1; offset >= 0; --offset) { int k = ++current[offset]; if (k < dimensions[offset]) { return; } current[offset] = 0; } } hasNext = false; } public void remove() { throw new UnsupportedOperationException(); } } // End CoordinateIterator.java olap4j-1.0.1.500/src/org/olap4j/impl/Olap4jUtil.java0000644000175000017500000005775411707255010021463 0ustar drazzibdrazzib/* // $Id: Olap4jUtil.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import org.olap4j.metadata.NamedList; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Utility methods common to multiple olap4j driver implementations. * *

      This class, and this package as a whole, are part of the olap4j library * but the methods are not part of the public olap4j API. The classes exist * for the convenience of implementers of olap4j drivers, but their * specification and implementation may change at any time.

      * *

      Applications which use the API in this package will not be portable * across multiple versions of olap4j. We encourage implementors of drivers * to use classes in this package, but not writers of applications.

      * * @author jhyde * @version $Id: Olap4jUtil.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 12, 2007 */ public class Olap4jUtil { /** * Whether we are running a version of Java before 1.5. * *

      If this variable is true, we will be running retroweaver. Retroweaver * has some problems involving {@link java.util.EnumSet}. */ public static final boolean PreJdk15 = System.getProperty("java.version").startsWith("1.4"); /** * Whether the code base has re-engineered using retroweaver. * If this is the case, some functionality is not available. */ public static final boolean Retrowoven = DummyEnum.class.getSuperclass().getName().equals( "com.rc.retroweaver.runtime.Enum_"); private static final Olap4jUtilCompatible compatible; private static final NamedList EMPTY_NAMED_LIST = new EmptyNamedList(); private static final Pattern CELL_VALUE_REGEX1 = Pattern.compile("\\s*([a-zA-Z][\\w\\.]*)\\s*=\\s*'([^']*)'"); private static final Pattern CELL_VALUE_REGEX2 = Pattern.compile("\\s*([a-zA-Z][\\w\\.]*)\\s*=\\s*([^\\s]*)"); static { String className; if (PreJdk15 || Retrowoven) { className = "org.olap4j.impl.Olap4jUtilCompatibleJdk14"; } else { className = "org.olap4j.impl.Olap4jUtilCompatibleJdk15"; } try { //noinspection unchecked Class clazz = (Class) Class.forName(className); compatible = clazz.newInstance(); } catch (ClassNotFoundException e) { throw new RuntimeException("Could not load '" + className + "'", e); } catch (InstantiationException e) { throw new RuntimeException("Could not load '" + className + "'", e); } catch (IllegalAccessException e) { throw new RuntimeException("Could not load '" + className + "'", e); } } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(boolean b) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(byte b) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(char c) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(double v) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(float v) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(int i) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(long l) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(Object o) { } @SuppressWarnings({"UnusedDeclaration"}) public static void discard(short i) { } /** * Casts a Set to a Set with a different element type. * * @param set Set * @return Set of desired type */ @SuppressWarnings({"unchecked"}) public static Set cast(Set set) { return (Set) set; } /** * Casts a List to a List with a different element type. * * @param list List * @return List of desired type */ @SuppressWarnings({"unchecked"}) public static List cast(List list) { return (List) list; } /** * Casts a NamedList to a NamedList with a different element type. * * @param list Named list * @return Named list of desired type */ @SuppressWarnings({"unchecked"}) public static NamedList cast(NamedList list) { return (NamedList) list; } /** * Returns a hashmap with given contents. * *

      Use this method in initializers. Type parameters are inferred from * context, and the contents are initialized declaratively. For example, * *

      Map<String, Integer> population =
      *   Olap4jUtil.mapOf(
      *     "UK", 65000000,
      *     "USA", 300000000);
      * * @see org.olap4j.impl.UnmodifiableArrayMap#of(Object, Object, Object...) * @see org.olap4j.impl.ArrayMap#of(Object, Object, Object...) * * @param key First key * @param value First value * @param keyValues Second and sequent key/value pairs * @param Key type * @param Value type * @return Map with given contents */ public static Map mapOf(K key, V value, Object... keyValues) { final Map map = new LinkedHashMap(1 + keyValues.length); map.put(key, value); for (int i = 0; i < keyValues.length;) { //noinspection unchecked map.put((K) keyValues[i++], (V) keyValues[i++]); } return map; } /** * Converts a Properties object to a Map with String keys and values. * * @param properties Properties * @return Map backed by the given Properties object */ public static Map toMap(final Properties properties) { return new AbstractMap() { public Set> entrySet() { return cast(properties.entrySet()); } }; } /** * Returns an exception indicating that we didn't expect to find this value * here. * * @param value Value * @return an AssertionError which can be thrown */ public static AssertionError unexpected(Enum value) { return new AssertionError( "Was not expecting value '" + value + "' for enumeration '" + value.getClass().getName() + "' in this context"); } /** * Returns true if two objects are equal, or are both null. * * @param t1 First value * @param t2 Second value * @return Whether values are both equal or both null */ public static boolean equal(T t1, T t2) { return t1 == null ? t2 == null : t1.equals(t2); } /** * Returns a string with every occurrence of a seek string replaced with * another. * * @param s String to act on * @param find String to find * @param replace String to replace it with * @return The modified string */ public static String replace( String s, String find, String replace) { // let's be optimistic int found = s.indexOf(find); if (found == -1) { return s; } StringBuilder sb = new StringBuilder(s.length() + 20); int start = 0; char[] chars = s.toCharArray(); final int step = find.length(); if (step == 0) { // Special case where find is "". sb.append(s); replace(sb, 0, find, replace); } else { for (;;) { sb.append(chars, start, found - start); if (found == s.length()) { break; } sb.append(replace); start = found + step; found = s.indexOf(find, start); if (found == -1) { found = s.length(); } } } return sb.toString(); } /** * Replaces all occurrences of a string in a buffer with another. * * @param buf String buffer to act on * @param start Ordinal within find to start searching * @param find String to find * @param replace String to replace it with * @return The string buffer */ public static StringBuilder replace( StringBuilder buf, int start, String find, String replace) { // Search and replace from the end towards the start, to avoid O(n ^ 2) // copying if the string occurs very commonly. int findLength = find.length(); if (findLength == 0) { // Special case where the seek string is empty. for (int j = buf.length(); j >= 0; --j) { buf.insert(j, replace); } return buf; } int k = buf.length(); while (k > 0) { int i = buf.lastIndexOf(find, k); if (i < start) { break; } buf.replace(i, i + find.length(), replace); // Step back far enough to ensure that the beginning of the section // we just replaced does not cause a match. k = i - findLength; } return buf; } /** * Converts a list of SQL-style patterns into a Java regular expression. * *

      For example, {"Foo_", "Bar%BAZ"} becomes "Foo.|Bar.*BAZ". * * @param wildcards List of SQL-style wildcard expressions * @return Regular expression */ public static String wildcardToRegexp(List wildcards) { StringBuilder buf = new StringBuilder(); for (String value : wildcards) { if (buf.length() > 0) { buf.append('|'); } int i = 0; while (true) { int percent = value.indexOf('%', i); int underscore = value.indexOf('_', i); if (percent == -1 && underscore == -1) { if (i < value.length()) { buf.append(quotePattern(value.substring(i))); } break; } if (underscore >= 0 && (underscore < percent || percent < 0)) { if (i < underscore) { buf.append( quotePattern(value.substring(i, underscore))); } buf.append('.'); i = underscore + 1; } else if (percent >= 0 && (percent < underscore || underscore < 0)) { if (i < percent) { buf.append( quotePattern(value.substring(i, percent))); } buf.append(".*"); i = percent + 1; } else { throw new IllegalArgumentException(); } } } return buf.toString(); } /** * Returns a literal pattern String for the specified String. * *

      Specification as for {@link java.util.regex.Pattern#quote(String)}, which was * introduced in JDK 1.5. * * @param s The string to be literalized * @return A literal string replacement */ public static String quotePattern(String s) { return compatible.quotePattern(s); } /** * Converts a camel-case name to an upper-case name with underscores. * *

      For example, camelToUpper("FooBar") returns "FOO_BAR". * * @param s Camel-case string * @return Upper-case string */ public static String camelToUpper(String s) { StringBuilder buf = new StringBuilder(s.length() + 10); int prevUpper = -1; for (int i = 0; i < s.length(); ++i) { char c = s.charAt(i); if (Character.isUpperCase(c)) { if (i > prevUpper + 1) { buf.append('_'); } prevUpper = i; } else { c = Character.toUpperCase(c); } buf.append(c); } return buf.toString(); } /** * Returns an exception which indicates that a particular piece of * functionality should work, but a developer has not implemented it yet. * * @param o Object operation was called on, perhaps indicating the * subtype where a virtual method needs to be implemented * * @return an exception which can be thrown */ public static RuntimeException needToImplement(Object o) { throw new UnsupportedOperationException("need to implement " + o); } /** * Parses a unique name. * *

      For example, uniqueNameToStringArray("[foo].[bar]") returns * {@code ["foo", "bar"]}. * * @see org.olap4j.mdx.IdentifierNode#parseIdentifier(String) * * @param uniqueName Unique name * @return Parsed unique name */ public static List parseUniqueName(String uniqueName) { List trail = new ArrayList(); Pattern regex = Pattern.compile("([^\\[\\]\\.]*)"); Matcher matcher = regex.matcher(uniqueName); while (matcher.find()) { String match = matcher.group(); if (!match.equals("")) { trail.add(match); } } return trail; } /** * Converts the contents of an array of strings to * a proper String representation. * * @param array Array of strings * @return string representation of the array */ public static String stringArrayToString(String[] array) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < array.length; i++) { sb.append(array[i]); if (i < (array.length - 1)) { sb.append(","); } } sb.append("]"); return sb.toString(); } @SuppressWarnings({"unchecked"}) public static NamedList emptyNamedList() { return (NamedList) EMPTY_NAMED_LIST; } /** * Returns an unmodifiable view of the specified list. This method allows * modules to provide users with "read-only" access to internal * lists. Query operations on the returned list "read through" to the * specified list, and attempts to modify the returned list, whether * direct or via its iterator, result in an * UnsupportedOperationException.

      * * The returned list will be serializable if the specified list * is serializable. Similarly, the returned list will implement * {@link RandomAccess} if the specified list does. * *

      The equivalent of * {@link java.util.Collections#unmodifiableList(java.util.List)}. * * @param list the list for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified list. */ public static NamedList unmodifiableNamedList( final NamedList list) { return list instanceof RandomAccess ? new UnmodifiableNamedRandomAccessList(list) : new UnmodifiableNamedList(list); } /** * Equivalent to {@link java.util.EnumSet#of(Enum, Enum[])} on JDK 1.5 or * later. Otherwise, returns an ordinary set. * * @param first an element that the set is to contain initially * @param rest the remaining elements the set is to contain initially * @throws NullPointerException if any of the specified elements are null, * or if rest is null * @return an enum set initially containing the specified elements */ public static > Set enumSetOf(E first, E... rest) { return compatible.enumSetOf(first, rest); } /** * Equivalent to {@link java.util.EnumSet#noneOf(Class)} on JDK 1.5 or * later. Otherwise, returns an ordinary set. * * @param elementType the class object of the element type for this enum * set * @return an empty enum set */ public static > Set enumSetNoneOf( Class elementType) { return compatible.enumSetNoneOf(elementType); } /** * Equivalent to {@link java.util.EnumSet#allOf(Class)} on JDK 1.5 or later. * Otherwise, returns an ordinary set. * @param elementType the class object of the element type for this enum * set * @return an enum set containing all elements of the given enum class */ public static > Set enumSetAllOf( Class elementType) { return compatible.enumSetAllOf(elementType); } /** * Parses a formatted cell values. * *

      There is a customary way of including formatting infornation in cell * values (started with Microsoft OLAP Services, and continued by JPivot and * now Pentaho Analyzer). This method parses out the formatted value that * should be displayed on the screen and also any properties present. * *

      Examples:

        *
      • "$123" no formatting information
      • *
      • "|$123|style=red|" print in red style
      • *
      • "|$123|style=red|arrow=up|" print in red style with an up arrow
      • *
      * *

      Properties

      * * * * * * * * * * * * * * * * * * * * * * * * * * * *
      NameValueDescription
      stylered|green|yellowrenders the Member in that color
      linka urlcreates a hyperlink on the member
      arrowup|down|blankpaints an arrow image
      imagea uri. If the uri starts with "/" the context name will be * prependedpaints image
      * * @param formattedValue Formatted cell value * @param map Map into which to place (property, value) pairs * @return Formatted cell value with properties removed */ public static String parseFormattedCellValue( String formattedValue, Map map) { if (formattedValue.startsWith("|")) { String[] strs = formattedValue.substring(1).split("\\|"); formattedValue = strs[0]; // original value for (int i = 1; i < strs.length; i++) { Matcher m = CELL_VALUE_REGEX1.matcher(strs[i]); if (m.matches()) { String propName = m.group(1); // property name String propValue = m.group(2); // property value map.put(propName, propValue); continue; } m = CELL_VALUE_REGEX2.matcher(strs[i]); if (m.matches()) { String propName = m.group(1); // property name String propValue = m.group(2); // property value map.put(propName, propValue); continue; } // it is not a key=value pair // we add the String to the formatted value formattedValue += strs[i]; } } return formattedValue; } private enum DummyEnum { } /** * Implementation of {@link NamedList} whih is immutable and empty. */ private static class EmptyNamedList extends AbstractNamedList { protected String getName(Object o) { throw new UnsupportedOperationException(); } public int size() { return 0; } public T get(int index) { throw new IndexOutOfBoundsException("Index: " + index); } // Preserves singleton property @SuppressWarnings({"UnusedDeclaration"}) private Object readResolve() { return EMPTY_NAMED_LIST; } } private static class UnmodifiableNamedList implements NamedList { private final NamedList list; UnmodifiableNamedList(NamedList list) { this.list = list; } public T get(String s) { return list.get(s); } public int indexOfName(String s) { return list.indexOfName(s); } public int size() { return list.size(); } public boolean isEmpty() { return list.isEmpty(); } public boolean contains(Object o) { return list.contains(o); } public Iterator iterator() { return Collections.unmodifiableList(list).iterator(); } public Object[] toArray() { return list.toArray(); } public T2[] toArray(T2[] a) { //noinspection SuspiciousToArrayCall return list.toArray(a); } public boolean add(T t) { throw new UnsupportedOperationException(); } public boolean remove(Object o) { throw new UnsupportedOperationException(); } public boolean containsAll(Collection c) { throw new UnsupportedOperationException(); } public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } public boolean addAll(int index, Collection c) { throw new UnsupportedOperationException(); } public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } public T get(int index) { return list.get(index); } public T set(int index, T element) { throw new UnsupportedOperationException(); } public void add(int index, T element) { throw new UnsupportedOperationException(); } public T remove(int index) { throw new UnsupportedOperationException(); } public int indexOf(Object o) { return list.indexOf(0); } public int lastIndexOf(Object o) { return list.lastIndexOf(o); } public ListIterator listIterator() { return Collections.unmodifiableList(list).listIterator(); } public ListIterator listIterator(int index) { return Collections.unmodifiableList(list).listIterator(index); } public List subList(int fromIndex, int toIndex) { // TODO: NamedList.subList should return NamedList. return Collections.unmodifiableList( list.subList(fromIndex, toIndex)); } } private static class UnmodifiableNamedRandomAccessList extends UnmodifiableNamedList implements RandomAccess { UnmodifiableNamedRandomAccessList(NamedList list) { super(list); } } } // End Olap4jUtil.java olap4j-1.0.1.500/src/org/olap4j/impl/Named.java0000644000175000017500000000247411707255010020505 0ustar drazzibdrazzib/* // $Id: Named.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; /** * Interface which describes an object which has a name, for the purposes of * creating an implementation, {@link NamedListImpl} of * {@link org.olap4j.metadata.NamedList} which works on such objects. * * @author jhyde * @version $Id: Named.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 23, 2007 */ public interface Named { /** * Returns the name of this object. * * @return name of this object */ String getName(); } // End Named.java olap4j-1.0.1.500/src/org/olap4j/impl/AbstractNamedList.java0000644000175000017500000000366311707255010023026 0ustar drazzibdrazzib/* // $Id: AbstractNamedList.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import org.olap4j.metadata.NamedList; import java.util.AbstractList; /** * Partial implementation of {@link org.olap4j.metadata.NamedList}. * *

      Derived class must implement {@link #get(int)} and {@link #size()}, as * per {@link java.util.AbstractList}; and must implement * {@link #getName(Object)}, to indicate how elements are named. * * @see org.olap4j.impl.ArrayNamedListImpl * * @author jhyde * @version $Id: AbstractNamedList.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 25, 2007 */ public abstract class AbstractNamedList extends AbstractList implements NamedList { protected abstract String getName(T t); public T get(String name) { for (T t : this) { if (getName(t).equals(name)) { return t; } } return null; } public int indexOfName(String name) { for (int i = 0; i < size(); ++i) { T t = get(i); if (getName(t).equals(name)) { return i; } } return -1; } } // End AbstractNamedList.java olap4j-1.0.1.500/src/org/olap4j/impl/Bug.java0000644000175000017500000000603611707255010020174 0ustar drazzibdrazzib/* // $Id: Bug.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; /** * Holder for constants which indicate whether particular issues have been * fixed. Reference one of those constants in your code, and it is clear which * code can be enabled when the bug is fixed. Generally a constant is removed * when its bug is fixed. * *

      Developers, please use the naming format * Bug<Product><Number>Fixed for constants, and include * a hyperlink to the bug database record in the comments. Product will usually * be "Olap4j", but sometimes we are blocked by bugs in other components, such * as the JDK or Mondrian. * *

      Cleanup items

      * * The following is a list of cleanup items. They are not bugs per se: * functionality is not wrong, just the organization of the code. If they were * bugs, they would be in jira. It makes sense to have the list here, so that * referenced class, method and variable names show up as uses in code searches. * *
      * *
      Split out Test Compatability Kit (TCK)
      *
      Factor parts of olap4j test suite that depend on an olap4j implementation * (such as mondrian) into a jar that can be invoked by that implementation. * Then each implementation is responsible for running the TCK. It can also * manage which version of the TCK it implements, so that it does not have to * be absolutely up to date. Some parts of the olap4j suite do not stretch the * capabilities of the OLAP engine or driver, and will remain part of * the olap4j suite, using mondrian as reference implementation.
      * *
      * * @author jhyde * @version $Id: Bug.java 482 2012-01-05 23:27:27Z jhyde $ * @since Nov 9, 2010 */ public abstract class Bug { /** * Whether * bug 3106220, * "Complex selection context broken" * is fixed. */ public static final boolean BugOlap4j3106220Fixed = false; /** * Whether * bug 3126853, * "ConnectionTest.testCellSetBug hangs" * is fixed. */ public static final boolean BugOlap4j3126853Fixed = false; } // End Bug.java olap4j-1.0.1.500/src/org/olap4j/impl/Pair.java0000644000175000017500000000567411707255010020361 0ustar drazzibdrazzib/* // $Id: Pair.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.Map; /** * Pair of values. * *

      Because a pair implements {@link #equals(Object)}, {@link #hashCode()} and * {@link #compareTo(Pair)}, it can be used in any kind of * {@link java.util.Collection}. * * @author jhyde * @version $Id: Pair.java 482 2012-01-05 23:27:27Z jhyde $ * @since Apr 19, 2007 */ class Pair implements Comparable>, Map.Entry { public L left; public R right; /** * Creates a pair. * * @param left Left value * @param right Right value */ public Pair(L left, R right) { this.left = left; this.right = right; } public boolean equals(Object obj) { if (obj instanceof Pair) { Pair pair = (Pair) obj; return Olap4jUtil.equal(this.left, pair.left) && Olap4jUtil.equal(this.right, pair.right); } return false; } public int hashCode() { // formula required by Map contract final int k = left == null ? 0 : left.hashCode(); final int k1 = right == null ? 0 : right.hashCode(); return k ^ k1; } public int compareTo(Pair that) { int c = compare((Comparable) this.left, (Comparable)that.left); if (c == 0) { c = compare((Comparable) this.right, (Comparable)that.right); } return c; } public String toString() { return "<" + left + ", " + right + ">"; } // implement Map.Entry public L getKey() { return left; } // implement Map.Entry public R getValue() { return right; } // implement Map.Entry public R setValue(R value) { R previous = right; right = value; return previous; } private static > int compare(C c1, C c2) { if (c1 == null) { if (c2 == null) { return 0; } else { return -1; } } else if (c2 == null) { return 1; } else { return c1.compareTo(c2); } } } // End Pair.java olap4j-1.0.1.500/src/org/olap4j/impl/Olap4jUtilCompatible.java0000644000175000017500000000457011707255010023447 0ustar drazzibdrazzib/* // $Id: Olap4jUtilCompatible.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.Set; /** * Interface containing methods which are implemented differently in different * versions of the JDK. * *

      The methods should not be called directly, only via the corresponding * static methods in {@link Olap4jUtil}, namely:

        *
      • {@link org.olap4j.impl.Olap4jUtil#quotePattern(String)}
      • *

      * *

      This interface could in principle be extended to allow native * implementations of methods, or to serve as a factory for entire classes * which have different implementations in different environments.

      * * @author jhyde * @version $Id: Olap4jUtilCompatible.java 482 2012-01-05 23:27:27Z jhyde $ * @since Feb 5, 2007 */ public interface Olap4jUtilCompatible { /** * Returns a literal pattern String for the specified String. * *

      Specification as for {@link java.util.regex.Pattern#quote(String)}, * which was introduced in JDK 1.5. * * @param s The string to be literalized * @return A literal string replacement */ String quotePattern(String s); /** * See {@link org.olap4j.impl.Olap4jUtil#enumSetOf(Enum, Enum[])}. */ > Set enumSetOf(E first, E... rest); /** * See {@link org.olap4j.impl.Olap4jUtil#enumSetNoneOf(Class)}. */ > Set enumSetNoneOf(Class elementType); /** * See {@link org.olap4j.impl.Olap4jUtil#enumSetAllOf(Class)}. */ > Set enumSetAllOf(Class elementType); } // End Olap4jUtilCompatible.java olap4j-1.0.1.500/src/org/olap4j/impl/NamedListImpl.java0000644000175000017500000000431211707255010022154 0ustar drazzibdrazzib/* // $Id: NamedListImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.Collection; /** * Implementation of {@link org.olap4j.metadata.NamedList} which uses * {@link java.util.ArrayList} for storage and assumes that elements implement * the {@link org.olap4j.impl.Named} interface. * * @author jhyde * @version $Id: NamedListImpl.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 23, 2007 */ public class NamedListImpl extends ArrayNamedListImpl { /** * Creates an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @exception IllegalArgumentException if the specified initial capacity * is negative */ public NamedListImpl(int initialCapacity) { super(initialCapacity); } /** * Creates an empty list. */ public NamedListImpl() { super(); } /** * Creates a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public NamedListImpl(Collection c) { super(c); } protected final String getName(T t) { return t.getName(); } } // End NamedListImpl.java olap4j-1.0.1.500/src/org/olap4j/impl/Olap4jUtilCompatibleJdk14.java0000644000175000017500000000444111707255010024242 0ustar drazzibdrazzib/* // $Id: Olap4jUtilCompatibleJdk14.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.*; /** * Implementation of {@link Olap4jUtilCompatible} which runs in * JDK 1.4. * * @author jhyde * @version $Id: Olap4jUtilCompatibleJdk14.java 482 2012-01-05 23:27:27Z jhyde $ * @since Feb 5, 2007 */ public class Olap4jUtilCompatibleJdk14 implements Olap4jUtilCompatible { public final String quotePattern(String s) { int slashEIndex = s.indexOf("\\E"); if (slashEIndex == -1) { return "\\Q" + s + "\\E"; } StringBuilder sb = new StringBuilder(s.length() * 2); sb.append("\\Q"); int current = 0; while ((slashEIndex = s.indexOf("\\E", current)) != -1) { sb.append(s.substring(current, slashEIndex)); current = slashEIndex + 2; sb.append("\\E\\\\E\\Q"); } sb.append(s.substring(current, s.length())); sb.append("\\E"); return sb.toString(); } public final > Set enumSetOf(E first, E... rest) { HashSet set = new HashSet(); set.add(first); set.addAll(Arrays.asList(rest)); return set; } public final > Set enumSetNoneOf(Class elementType) { return new HashSet(); } public final > Set enumSetAllOf(Class elementType) { return new HashSet(Arrays.asList(elementType.getEnumConstants())); } } // End Olap4jUtilCompatibleJdk14.java olap4j-1.0.1.500/src/org/olap4j/impl/ArrayNamedListImpl.java0000644000175000017500000000534511707255010023162 0ustar drazzibdrazzib/* // $Id: ArrayNamedListImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import org.olap4j.metadata.NamedList; import java.util.ArrayList; import java.util.Collection; /** * Implementation of {@link org.olap4j.metadata.NamedList} which uses * {@link java.util.ArrayList} for storage. * *

      Derived class must implement {@link #getName(Object)}, to indicate how * elements are named. * * @see NamedListImpl * * @author jhyde * @version $Id: ArrayNamedListImpl.java 482 2012-01-05 23:27:27Z jhyde $ * @since Nov 12, 2007 */ public abstract class ArrayNamedListImpl extends ArrayList implements NamedList { /** * Creates an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @exception IllegalArgumentException if the specified initial capacity * is negative */ public ArrayNamedListImpl(int initialCapacity) { super(initialCapacity); } /** * Creates an empty list. */ public ArrayNamedListImpl() { super(); } /** * Creates a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayNamedListImpl(Collection c) { super(c); } protected abstract String getName(T t); public T get(String name) { for (T t : this) { if (getName(t).equals(name)) { return t; } } return null; } public int indexOfName(String name) { for (int i = 0; i < size(); ++i) { T t = get(i); if (getName(t).equals(name)) { return i; } } return -1; } } // End ArrayNamedListImpl.java olap4j-1.0.1.500/src/org/olap4j/impl/IdentifierParser.java0000644000175000017500000003566211707255010022725 0ustar drazzibdrazzib/* // $Id: IdentifierParser.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import org.olap4j.mdx.*; import java.util.ArrayList; import java.util.List; /** * Utilities for parsing fully-qualified member names, tuples, member lists, * and tuple lists. * *

      NOTE: Like other classes in the org.olap4j.impl package, this class * is not part of the public olap4j API. It is subject to change or removal * without notice. It is provided in the hope that it will be useful to * implementors of olap4j drivers. * * @version $Id: IdentifierParser.java 482 2012-01-05 23:27:27Z jhyde $ * @author jhyde */ public class IdentifierParser { // lexical states private static final int START = 0; private static final int BEFORE_SEG = 1; private static final int IN_BRACKET_SEG = 2; private static final int AFTER_SEG = 3; private static final int IN_SEG = 4; private static char charAt(String s, int pos) { return pos < s.length() ? s.charAt(pos) : 0; } /** * Parses a list of tuples (or a list of members). * * @param builder Builder, called back when each segment, member and tuple * is complete. * @param string String to parse */ public static void parseTupleList( Builder builder, String string) { int i = 0; char c; while ((c = charAt(string, i++)) == ' ') { } if (c != '{') { throw fail(string, i, "{"); } while (true) { i = parseTuple(builder, string, i); while ((c = charAt(string, i++)) == ' ') { } if (c == ',') { // fine } else if (c == '}') { // we're done return; } else { throw fail(string, i, ", or }"); } } } /** * Parses a tuple, of the form '(member, member, ...)', and calls builder * methods when finding a segment, member or tuple. * * @param builder Builder * @param string String to parse * @param i Position to start parsing in string * @return Position where parsing ended in string */ public static int parseTuple( Builder builder, String string, int i) { char c; while ((c = charAt(string, i++)) == ' ') { } if (c != '(') { throw fail(string, i, "("); } while (true) { i = parseMember(builder, string, i); while ((c = charAt(string, i++)) == ' ') { } if (c == ',') { // fine } else if (c == ')') { builder.tupleComplete(); break; } } return i; } public static void parseMemberList( Builder builder, String string) { int i = 0; char c = charAt(string, i); while (c > 0 && c <= ' ') { c = charAt(string, ++i); } boolean leadingBrace = false; boolean trailingBrace = false; if (c == '{') { leadingBrace = true; ++i; } w: while (true) { i = parseMember(builder, string, i); c = charAt(string, i); while (c > 0 && c <= ' ') { c = charAt(string, ++i); } switch (c) { case 0: break w; case ',': // fine ++i; break; case '}': // we're done trailingBrace = true; break w; default: throw fail(string, i, ", or }"); } } if (leadingBrace != trailingBrace) { throw new IllegalArgumentException( "mismatched '{' and '}' in '" + string + "'"); } } public static int parseMember( Builder builder, String string, int i) { int k = string.length(); int state = START; int start = 0; Builder.Syntax syntax = Builder.Syntax.NAME; char c; loop: while (i < k + 1) { c = charAt(string, i); switch (state) { case START: case BEFORE_SEG: switch (c) { case '[': ++i; start = i; state = IN_BRACKET_SEG; break; case ' ': // Skip whitespace, don't change state. ++i; break; case ',': case '}': case 0: break loop; case '.': // TODO: test this, case: ".abc" throw new IllegalArgumentException("unexpected: '.'"); case '&': // Note that we have seen ampersand, but don't change state. ++i; if (syntax != Builder.Syntax.NAME) { throw new IllegalArgumentException("unexpected: '&'"); } syntax = Builder.Syntax.FIRST_KEY; break; default: // Carry on reading. state = IN_SEG; start = i; break; } break; case IN_SEG: switch (c) { case ',': case ')': case '}': case 0: builder.segmentComplete( null, string.substring(start, i).trim(), Quoting.UNQUOTED, syntax); state = AFTER_SEG; break loop; case '.': builder.segmentComplete( null, string.substring(start, i).trim(), Quoting.UNQUOTED, syntax); syntax = Builder.Syntax.NAME; state = BEFORE_SEG; ++i; break; case '&': builder.segmentComplete( null, string.substring(start, i).trim(), Quoting.UNQUOTED, syntax); syntax = Builder.Syntax.NEXT_KEY; state = BEFORE_SEG; ++i; break; default: ++i; } break; case IN_BRACKET_SEG: switch (c) { case 0: throw new IllegalArgumentException( "Expected ']', in member identifier '" + string + "'"); case ']': if (charAt(string, i + 1) == ']') { ++i; // fall through } else { builder.segmentComplete( null, Olap4jUtil.replace( string.substring(start, i), "]]", "]"), Quoting.QUOTED, syntax); ++i; state = AFTER_SEG; break; } default: // Carry on reading. ++i; } break; case AFTER_SEG: switch (c) { case ' ': // Skip over any spaces // TODO: test this case: '[foo] . [bar]' ++i; break; case '.': state = BEFORE_SEG; syntax = Builder.Syntax.NAME; ++i; break; case '&': state = BEFORE_SEG; if (syntax == Builder.Syntax.FIRST_KEY) { syntax = Builder.Syntax.NEXT_KEY; } else { syntax = Builder.Syntax.FIRST_KEY; } ++i; break; default: // We're not looking at the start of a segment. Parse // the member we've seen so far, then return. break loop; } break; default: throw new AssertionError("unexpected state: " + state); } } switch (state) { case START: return i; case BEFORE_SEG: throw new IllegalArgumentException( "Expected identifier after '.', in member identifier '" + string + "'"); case IN_BRACKET_SEG: throw new IllegalArgumentException( "Expected ']', in member identifier '" + string + "'"); } // End of member. builder.memberComplete(); return i; } private static IllegalArgumentException fail( String string, int i, String expecting) { throw new IllegalArgumentException( "expected '" + expecting + "' at position " + i + " in '" + string + "'"); } /** * Parses an MDX identifier such as [Foo].[Bar].Baz.&Key&Key2 * and returns the result as a list of segments. * * @param s MDX identifier * @return List of segments */ public static List parseIdentifier(String s) { final MemberBuilder builder = new MemberBuilder(); int i = parseMember(builder, s, 0); if (i < s.length()) { throw new IllegalArgumentException( "Invalid member identifier '" + s + "'"); } return builder.segmentList; } /** * Parses a string consisting of a sequence of MDX identifiers and returns * the result as a list of compound identifiers, each of which is a list * of segments. * *

      For example, parseIdentifierList("{foo.bar, baz}") returns * { {"foo", "bar"}, {"baz"} }. * *

      The braces around the list are optional; * parseIdentifierList("foo.bar, baz") returns the same result as the * previous example. * * @param s MDX identifier list * @return List of lists of segments */ public static List> parseIdentifierList( String s) { final MemberListBuilder builder = new MemberListBuilder(); parseMemberList(builder, s); return builder.list; } /** * Callback that is called on completion of a structural element like a * member or tuple. * *

      Implementations might create a list of members or just create a list * of unresolved names. */ public interface Builder { /** * Called when a tuple is complete. */ void tupleComplete(); /** * Called when a member is complete. */ void memberComplete(); /** * Called when a segment is complete. * *

      For example, the identifier {@code [Time].1997.[Jan].&31} contains * four name segments: "[Time]", "1997", "[Jan]" and "31". The first * and third are quoted; the last has an ampersand signifying that it * is a key. * * @param region Region of source code * @param name Name * @param quoting Quoting style * @param syntax Whether this is a name segment, first part of a key * segment, or continuation of a key segment */ void segmentComplete( ParseRegion region, String name, Quoting quoting, Syntax syntax); enum Syntax { NAME, FIRST_KEY, NEXT_KEY } } /** * Implementation of {@link org.olap4j.impl.IdentifierParser.Builder} * that collects the segments that make up the name of a member in a list. * It cannot handle tuples or lists of members. */ public static class MemberBuilder implements Builder { protected final List subSegments; protected final List segmentList; public MemberBuilder() { segmentList = new ArrayList(); subSegments = new ArrayList(); } public void tupleComplete() { throw new UnsupportedOperationException(); } public void memberComplete() { flushSubSegments(); } private void flushSubSegments() { if (!subSegments.isEmpty()) { segmentList.add(new KeySegment(subSegments)); subSegments.clear(); } } public void segmentComplete( ParseRegion region, String name, Quoting quoting, Syntax syntax) { final NameSegment segment = new NameSegment( region, name, quoting); if (syntax != Syntax.NEXT_KEY) { // If we were building a previous key, write it out. // E.g. [Foo].&1&2.&3&4&5. flushSubSegments(); } if (syntax == Syntax.NAME) { segmentList.add(segment); } else { subSegments.add(segment); } } } /** * Implementation of {@link org.olap4j.impl.IdentifierParser.Builder} * that collects segments into members, * then collects members into lists. */ public static class MemberListBuilder extends MemberBuilder { final List> list = new ArrayList>(); public void memberComplete() { super.memberComplete(); list.add( new ArrayList(segmentList)); segmentList.clear(); } } } // End IdentifierParser.java olap4j-1.0.1.500/src/org/olap4j/impl/LcidLocale.java0000644000175000017500000002265111707255010021453 0ustar drazzibdrazzib/* // $Id: LcidLocale.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.*; /** * Mapping between {@link Locale} and Locale identifier (LCID). * * @version $Id: LcidLocale.java 483 2012-01-05 23:43:18Z jhyde $ * @author jhyde */ public class LcidLocale { final Map lcidLocaleMap = new HashMap(); final Map localeToLcidMap = new HashMap(); private static final Object[] LOCALE_DATA = { "ar", (short) 0x0401, "bg", (short) 0x0402, "ca", (short) 0x0403, "zh", (short) 0x0404, "cs", (short) 0x0405, "da", (short) 0x0406, "de", (short) 0x0407, "el", (short) 0x0408, "es", (short) 0x040a, "fi", (short) 0x040b, "fr", (short) 0x040c, "iw", (short) 0x040d, "hu", (short) 0x040e, "is", (short) 0x040f, "it", (short) 0x0410, "ja", (short) 0x0411, "ko", (short) 0x0412, "nl", (short) 0x0413, "no", (short) 0x0414, "pl", (short) 0x0415, "pt", (short) 0x0416, "rm", (short) 0x0417, "ro", (short) 0x0418, "ru", (short) 0x0419, "hr", (short) 0x041a, "sk", (short) 0x041b, "sq", (short) 0x041c, "sv", (short) 0x041d, "th", (short) 0x041e, "tr", (short) 0x041f, "ur", (short) 0x0420, "in", (short) 0x0421, "uk", (short) 0x0422, "be", (short) 0x0423, "sl", (short) 0x0424, "et", (short) 0x0425, "lv", (short) 0x0426, "lt", (short) 0x0427, "fa", (short) 0x0429, "vi", (short) 0x042a, "hy", (short) 0x042b, "eu", (short) 0x042d, "mk", (short) 0x042f, "tn", (short) 0x0432, "xh", (short) 0x0434, "zu", (short) 0x0435, "af", (short) 0x0436, "ka", (short) 0x0437, "fo", (short) 0x0438, "hi", (short) 0x0439, "mt", (short) 0x043a, "se", (short) 0x043b, "gd", (short) 0x043c, "ms", (short) 0x043e, "kk", (short) 0x043f, "ky", (short) 0x0440, "sw", (short) 0x0441, "tt", (short) 0x0444, "bn", (short) 0x0445, "pa", (short) 0x0446, "gu", (short) 0x0447, "ta", (short) 0x0449, "te", (short) 0x044a, "kn", (short) 0x044b, "ml", (short) 0x044c, "mr", (short) 0x044e, "sa", (short) 0x044f, "mn", (short) 0x0450, "cy", (short) 0x0452, "gl", (short) 0x0456, "dv", (short) 0x0465, "qu", (short) 0x046b, "mi", (short) 0x0481, "ar_IQ", (short) 0x0801, "zh_CN", (short) 0x0804, "de_CH", (short) 0x0807, "en_GB", (short) 0x0809, "es_MX", (short) 0x080a, "fr_BE", (short) 0x080c, "it_CH", (short) 0x0810, "nl_BE", (short) 0x0813, "no_NO_NY", (short) 0x0814, "pt_PT", (short) 0x0816, "ro_MD", (short) 0x0818, "ru_MD", (short) 0x0819, "sr_CS", (short) 0x081a, "sv_FI", (short) 0x081d, "az_AZ", (short) 0x082c, "se_SE", (short) 0x083b, "ga_IE", (short) 0x083c, "ms_BN", (short) 0x083e, "uz_UZ", (short) 0x0843, "qu_EC", (short) 0x086b, "ar_EG", (short) 0x0c01, "zh_HK", (short) 0x0c04, "de_AT", (short) 0x0c07, "en_AU", (short) 0x0c09, "fr_CA", (short) 0x0c0c, "sr_CS", (short) 0x0c1a, "se_FI", (short) 0x0c3b, "qu_PE", (short) 0x0c6b, "ar_LY", (short) 0x1001, "zh_SG", (short) 0x1004, "de_LU", (short) 0x1007, "en_CA", (short) 0x1009, "es_GT", (short) 0x100a, "fr_CH", (short) 0x100c, "hr_BA", (short) 0x101a, "ar_DZ", (short) 0x1401, "zh_MO", (short) 0x1404, "de_LI", (short) 0x1407, "en_NZ", (short) 0x1409, "es_CR", (short) 0x140a, "fr_LU", (short) 0x140c, "bs_BA", (short) 0x141a, "ar_MA", (short) 0x1801, "en_IE", (short) 0x1809, "es_PA", (short) 0x180a, "fr_MC", (short) 0x180c, "sr_BA", (short) 0x181a, "ar_TN", (short) 0x1c01, "en_ZA", (short) 0x1c09, "es_DO", (short) 0x1c0a, "sr_BA", (short) 0x1c1a, "ar_OM", (short) 0x2001, "en_JM", (short) 0x2009, "es_VE", (short) 0x200a, "ar_YE", (short) 0x2401, "es_CO", (short) 0x240a, "ar_SY", (short) 0x2801, "en_BZ", (short) 0x2809, "es_PE", (short) 0x280a, "ar_JO", (short) 0x2c01, "en_TT", (short) 0x2c09, "es_AR", (short) 0x2c0a, "ar_LB", (short) 0x3001, "en_ZW", (short) 0x3009, "es_EC", (short) 0x300a, "ar_KW", (short) 0x3401, "en_PH", (short) 0x3409, "es_CL", (short) 0x340a, "ar_AE", (short) 0x3801, "es_UY", (short) 0x380a, "ar_BH", (short) 0x3c01, "es_PY", (short) 0x3c0a, "ar_QA", (short) 0x4001, "es_BO", (short) 0x400a, "es_SV", (short) 0x440a, "es_HN", (short) 0x480a, "es_NI", (short) 0x4c0a, "es_PR", (short) 0x500a, }; /** * The singleton instance. Initialized lazily, to avoid the space overhead * of the full map. (Most people only use LCID 1033 = en_US.) */ private static LcidLocale INSTANCE; private LcidLocale() { for (int i = 0; i < LOCALE_DATA.length;) { String localeName = (String) LOCALE_DATA[i++]; Short lcid = (Short) LOCALE_DATA[i++]; lcidLocaleMap.put(lcid, localeName); localeToLcidMap.put(localeName, lcid); } } /** * Returns the singleton instance, creating if necessary. */ static LcidLocale instance() { if (INSTANCE == null) { INSTANCE = new LcidLocale(); } return INSTANCE; } /** * Converts a locale id to a locale. * * @param lcid LCID * @return Locale, never null * @throws RuntimeException if LCID is not valid */ private Locale toLocale(short lcid) { final String s = lcidLocaleMap.get(lcid); if (s == null) { throw new RuntimeException("Unknown LCID " + lcid); } return parseLocale(s); } /** * Converts a locale identifier (LCID) as used by Windows into a Java * locale. * *

      For example, {@code lcidToLocale(1033)} returns "en_US", because * 1033 (hex 0409) is US english.

      * * @param lcid Locale identifier * @return Locale * @throws RuntimeException if locale id is unkown */ public static Locale lcidToLocale(short lcid) { // Most common case first, to avoid instantiating the full map. if (lcid == 0x0409) { return Locale.US; } return instance().toLocale(lcid); } /** * Converts a locale name to a locale identifier (LCID). * *

      For example, {@code localeToLcid(Locale.US)} returns 1033, * because 1033 (hex 0409) is US english.

      * * @param locale Locale * @return Locale identifier * @throws RuntimeException if locale has no known LCID */ public static short localeToLcid(Locale locale) { // Most common case first, to avoid instantiating the full map. if (locale.equals(Locale.US)) { return 0x0409; } return instance().toLcid(locale.toString()); } private short toLcid(String localeName) { final String localeName0 = localeName; for (;;) { final Short lcid = localeToLcidMap.get(localeName); if (lcid != null) { return lcid; } final int underscore = localeName.lastIndexOf('_'); if (underscore < 0) { throw new RuntimeException("Unknown locale " + localeName0); } localeName = localeName.substring(0, underscore); } } /** * Parses a locale string. * *

      The inverse operation of {@link java.util.Locale#toString()}. * * @param localeString Locale string, e.g. "en" or "en_US" * @return Java locale object */ public static Locale parseLocale(String localeString) { String[] strings = localeString.split("_"); switch (strings.length) { case 1: return new Locale(strings[0]); case 2: return new Locale(strings[0], strings[1]); case 3: return new Locale(strings[0], strings[1], strings[2]); default: throw new RuntimeException( "bad locale string '" + localeString + "'"); } } } // End LcidLocale.java olap4j-1.0.1.500/src/org/olap4j/impl/UnmodifiableArrayList.java0000644000175000017500000000575011707255010023712 0ustar drazzibdrazzib/* // $Id: UnmodifiableArrayList.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.*; /** * Unmodifiable list backed by an array. * *

      The traditional solution to this problem is to call * {@link java.util.Arrays#asList(Object[])} followed by * {@link java.util.Collections#unmodifiableList(java.util.List)}, but this * class has one fewer wrapper object, saving space and indirection effort. * * @author jhyde * @version $Id: UnmodifiableArrayList.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 7, 2009 */ public class UnmodifiableArrayList extends AbstractList implements List { private final T[] elements; /** * Creates an UnmodifiableArrayList. * *

      Does not create a copy of the array. Future changes to the array will * be reflected in the contents of the list. * * @param elements Array */ public UnmodifiableArrayList(T... elements) { this.elements = elements; } public T get(int index) { return elements[index]; } public int size() { return elements.length; } /** * Creates an unmodifable list as a shallow copy of an array. * *

      Future changes to the array will not be reflected in the contents * of the list. * * @param elements Elements of list * @param Type of elements * @return Unmodifiable list with same contents that the array had at call * time */ public static UnmodifiableArrayList asCopyOf(T... elements) { return new UnmodifiableArrayList(elements.clone()); } /** * Creates an unmodifable list as a shallow copy of a collection. * *

      Future changes to the collection will not be reflected in the contents * of the list. * * @param collection Elements of list * @param Type of elements * @return Unmodifiable list with same contents that the collection had at * call time */ public static UnmodifiableArrayList of( Collection collection) { //noinspection unchecked return new UnmodifiableArrayList( (T[]) collection.toArray()); } } // End UnmodifiableArrayList.java olap4j-1.0.1.500/src/org/olap4j/impl/UnmodifiableArrayMap.java0000644000175000017500000000761511707255010023516 0ustar drazzibdrazzib/* // $Id: UnmodifiableArrayMap.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.Collections; import java.util.Map; /** * Unmodifiable map backed by an array. * *

      Has the same benefits and limitations as {@link ArrayMap}. It is extremely * space-efficient but has poor performance for insert and lookup. * *

      This structure is ideal if you are creating many maps with few elements. * The {@link #of(java.util.Map)} method will use * {@link java.util.Collections#emptyMap} and * {@link java.util.Collections#singletonMap(Object, Object)} if possible, and * these are even more space-efficient for maps of size 0 and 1. * * @author jhyde * @version $Id: UnmodifiableArrayMap.java 482 2012-01-05 23:27:27Z jhyde $ * @since Jan 16, 2010 */ public class UnmodifiableArrayMap extends ArrayMap { /** * Creates an UnmodifiableArrayMap. * * @param map Contents of map, copied on creation */ public UnmodifiableArrayMap(Map map) { super(map); } @Override public V put(K key, V value) { throw new UnsupportedOperationException(); } @Override public V remove(Object key) { throw new UnsupportedOperationException(); } @Override public void putAll(Map m) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } /** * Returns an unmodifiable array map with given contents. * * @param key First key * @param value First value * @param keyValues Second and sequent key/value pairs * @param Key type * @param Value type * @return Map with given contents */ public static Map of( K key, V value, Object... keyValues) { if (keyValues.length == 0) { return Collections.singletonMap(key, value); } // Because UnmodifiableArrayMap is so bad at bulk inserts, it makes // sense to build another map just so we can populate the // UnmodifiableArrayMap in one shot. We require that the other map // preserves order; luckily mapOf uses LinkedHashMap. return new UnmodifiableArrayMap( Olap4jUtil.mapOf(key, value, keyValues)); } /** * Creates an unmodifable map as a shallow copy of a map. * *

      Future changes to the map will not be reflected in the contents * of the map. * * @param Key type * @param Value type * @return Unmodifiable map with same contents that the map had at * call time */ public static Map of( Map map) { switch (map.size()) { case 0: return Collections.emptyMap(); case 1: final Entry entry = map.entrySet().iterator().next(); return Collections.singletonMap(entry.getKey(), entry.getValue()); default: //noinspection unchecked return new UnmodifiableArrayMap(map); } } } // End UnmodifiableArrayMap.java olap4j-1.0.1.500/src/org/olap4j/impl/ArrayMap.java0000644000175000017500000002243611707255010021175 0ustar drazzibdrazzib/* // $Id: ArrayMap.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.impl; import java.util.*; /** * Implementation of {@link java.util.Map} which uses an array and is therefore * not very fast but very space-efficient. * *

      This implementation uses very little space but is inefficient. The * operations {@link #put}, {@link #remove}, {@link #get} all take time * proportional to the number of keys. * * @author jhyde * @version $Id: ArrayMap.java 482 2012-01-05 23:27:27Z jhyde $ * @since Dec 9, 2007 */ public class ArrayMap implements Map { private static final Object[] EMPTY_OBJECTS = new Object[0]; private Object[] keyValues; /** * Creates an empty ArrayMap. */ public ArrayMap() { keyValues = EMPTY_OBJECTS; } /** * Creates an ArrayMap whose contents the same as the given * map. * *

      This method is a more efficient way to build a large array than * repeatly calling {@link #put} or even calling {@link #putAll}. * * @param map Map */ public ArrayMap(Map map) { keyValues = new Object[map.size() * 2]; int i = 0; for (Entry entry : map.entrySet()) { keyValues[i++] = entry.getKey(); keyValues[i++] = entry.getValue(); } } /** * Returns an array map with given contents. * * @param key First key * @param value First value * @param keyValues Second and sequent key/value pairs * @param Key type * @param Value type * @return Map with given contents */ public static Map of( K key, V value, Object... keyValues) { // Because ArrayMap is so bad at bulk inserts, it makes sense to build // another map (HashMap) just so we can populate the ArrayMap in one // shot. return new ArrayMap(Olap4jUtil.mapOf(key, value, keyValues)); } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Map)) { return false; } Map m = (Map) o; if (m.size() != size()) { return false; } try { for (Entry e : entrySet()) { K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(m.get(key) == null && m.containsKey(key))) { return false; } } else { if (!value.equals(m.get(key))) { return false; } } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; } public int hashCode() { int h = 0; Iterator> i = entrySet().iterator(); while (i.hasNext()) { h += i.next().hashCode(); } return h; } public int size() { return keyValues.length / 2; } public boolean isEmpty() { return keyValues.length == 0; } public boolean containsKey(Object key) { return indexOfKey(key) >= 0; } private int indexOfKey(Object key) { for (int i = 0; i < keyValues.length; i += 2) { if (Olap4jUtil.equal(keyValues[i], key)) { return i; } } return -1; } public boolean containsValue(Object value) { for (int i = 1; i < keyValues.length; i += 2) { if (Olap4jUtil.equal(keyValues[i], value)) { return true; } } return false; } public V get(Object key) { final int i = indexOfKey(key); if (i >= 0) { return (V) keyValues[i + 1]; } return null; } public V put(K key, V value) { final int i = indexOfKey(key); if (i >= 0) { V v = (V) keyValues[i + 1]; keyValues[i + 1] = value; return v; } else { Object[] old = keyValues; keyValues = new Object[keyValues.length + 2]; System.arraycopy(old, 0, keyValues, 0, old.length); keyValues[old.length] = key; keyValues[old.length + 1] = value; return null; } } public V remove(Object key) { final int i = indexOfKey(key); if (i >= 0) { V v = (V) keyValues[i + 1]; removeInternal(i); return v; } else { // not present return null; } } private void removeInternal(int i) { if (keyValues.length == 2) { keyValues = EMPTY_OBJECTS; } Object[] old = keyValues; keyValues = new Object[keyValues.length - 2]; System.arraycopy(old, 0, keyValues, 0, i); System.arraycopy(old, i + 2, keyValues, i, old.length - i - 2); } public void putAll(Map m) { if (keyValues.length == 0) { // Efficient implementation of common case where map is initially // empty; otherwise we have O(n^2) reallocs. keyValues = new Object[m.size() * 2]; int i = 0; for (Entry entry : m.entrySet()) { keyValues[i++] = entry.getKey(); keyValues[i++] = entry.getValue(); } } else { // This algorithm is O(n^2): not great if m is large. But it's // difficult to preallocate the array if we don't know how many // keys overlap between this and m. for (Entry entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } } } public void clear() { keyValues = EMPTY_OBJECTS; } public Set keySet() { return new KeySet(); } public Collection values() { return new ValueList(); } public Set> entrySet() { return new EntrySet(); } public String toString() { Iterator> i = entrySet().iterator(); if (! i.hasNext()) { return "{}"; } StringBuilder sb = new StringBuilder(); sb.append('{'); for (;;) { Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key); sb.append('='); sb.append(value == this ? "(this Map)" : value); if (! i.hasNext()) { return sb.append('}').toString(); } sb.append(", "); } } private class KeySet extends AbstractSet { public Iterator iterator() { return new Iterator() { int i = 0; public boolean hasNext() { return i < keyValues.length; } public K next() { K k = (K) keyValues[i]; i += 2; return k; } public void remove() { removeInternal(i); } }; } public int size() { return ArrayMap.this.size(); } } private class ValueList extends AbstractList { public V get(int index) { return (V) keyValues[index * 2 + 1]; } public int size() { return keyValues.length / 2; } } private class EntrySet extends AbstractSet> { public Iterator> iterator() { return new Iterator>() { int i = 0; public boolean hasNext() { return i < keyValues.length; } public Entry next() { // We would use AbstractMap.SimpleEntry but it is not public // until JDK 1.6. final Entry entry = new Pair( (K) keyValues[i], (V) keyValues[i + 1]); i += 2; return entry; } public void remove() { removeInternal(i); } }; } public int size() { return ArrayMap.this.size(); } } } // End ArrayMap.java olap4j-1.0.1.500/src/org/olap4j/Cell.java0000644000175000017500000001514411707255012017377 0ustar drazzibdrazzib/* // $Id: Cell.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.metadata.Property; import java.sql.ResultSet; import java.util.List; /** * Cell returned from a {@link CellSet}. * * @author jhyde * @version $Id: Cell.java 482 2012-01-05 23:27:27Z jhyde $ * @since Aug 22, 2006 */ public interface Cell { /** * Returns the {@link CellSet} that this Cell belongs to. * * @return CellSet, never null */ CellSet getCellSet(); /** * Returns the ordinal of this Cell. * *

      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 CellSet}. 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.
      • *
      * * @return Ordinal of this Cell */ int getOrdinal(); /** * Returns the coordinates of this Cell in its {@link CellSetAxis}. * *

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

      * * getResult().ordinalToCoordinateList(getOrdinal()) * *
      * * @return Coordinates of this Cell */ List getCoordinateList(); /** * Returns the value of a given property for this Cell. * *

      The list of allowable properties may be obtained by calling * {@link org.olap4j.CellSet#getMetaData()} followed by * {@link CellSetMetaData#getCellProperties()}.

      * *

      Every cell has certain system properties such as "VALUE" and * "FORMAT_STRING" (the full list is described in the * {@link org.olap4j.metadata.Property.StandardCellProperty} * enumeration), as well as extra properties defined by the query.

      * * @param property Property whose value to retrieve * * @return Value of the given property for this Cell; if the property is * not set, returns null */ 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. * *

      Not all values can be represented as using the Java * double, therefore for some providers, {@link #getValue()} * may return a more accurate result. * * @return The value of this cell; if the cell is null, the * returns 0 * * @throws OlapException if this cell does not have a numeric value */ double getDoubleValue() throws OlapException; /** * Returns the error message of this Cell, or null if the cell is not * in error. * *

      If the cell is an error, the value will be an {@link OlapException}. * (This value is returned, not thrown.) * * @return value of this Cell */ String getErrorText(); /** * Returns the value of this Cell. * *

      If the cell is an error, the value will be an {@link OlapException}. * (This value is returned, not thrown.) * *

      If the cell has a numeric value, returns an object which implements * the {@link Number} interface. * * @see #getDoubleValue() * * @return value of this Cell */ Object getValue(); /** * Returns the value of this Cell, formatted according to the * FORMAT_STRING property and using the numeric formatting tokens the * current locale. * *

      The formatted value is never null. In particular, when the cell * contains the MDX NULL value, {@link #getValue()} will return the Java * null value but this method will return the empty string * "". * * @return Formatted value of this Cell */ String getFormattedValue(); /** * Drills through from this cell to the underlying fact table data, * and returns a {@link java.sql.ResultSet} of the results. * *

      If drill-through is not possible, returns null. * * @return result set of the fact rows underlying this Cell * * @throws OlapException if a database error occurs */ ResultSet drillThrough() throws OlapException; /** * Sets the value of a cell. * *

      When this method may be called depends on the provider. But typically, * the connection must at least have an active scenario; see * {@link OlapConnection#setScenario(Scenario)}. * *

      The number and type of additional arguments specified in the * {@code allocationArgs} parameter depends on the allocation policy chosen. * Some policies, such as {@link AllocationPolicy#EQUAL_ALLOCATION}, do not * require any additional arguments, in which case {@code allocationArgs} * may be {@code null}. * * @param value Cell value * @param allocationPolicy Allocation policy * @param allocationArgs Allocation policy arguments * * @throws OlapException if a database error occurs */ void setValue( Object value, AllocationPolicy allocationPolicy, Object... allocationArgs) throws OlapException; } // End Cell.java olap4j-1.0.1.500/src/org/olap4j/query/0000755000175000017500000000000011651266466017032 5ustar drazzibdrazzibolap4j-1.0.1.500/src/org/olap4j/query/Selection.java0000644000175000017500000001076511707255010021614 0ustar drazzibdrazzib/* // $Id: Selection.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.Dimension; import org.olap4j.metadata.MetadataElement; import java.util.List; /** * A selection of members from an OLAP dimension hierarchy. The selection * is a conceptual list of members from a given hierarchy. Once a selection * object is created, one can decide to include or exclude this selection * of members from the resulting query. * *

      Concrete subclasses of this represent a real selection. * Selections include things such as 'children of', 'siblings of', * 'descendents of' etc. * *

      This class is different from a {@link org.olap4j.metadata.Member} because it represents an * abstract member selection (e.g. children of widget' that may not represent * any members whereas a Member represents a single member that is known to * exist. * * @author jdixon, jhyde, Luc Boudreau * @version $Id: Selection.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 30, 2007 */ public interface Selection extends QueryNode { /** * Unique name of the selection root. * @return The unique OLAP name of the selection root. */ String getUniqueName(); /** * Visitor pattern-like function to convert * the selection into a ParseTreeNode. Typical * implementation should be:
      * Olap4jNodeConverter.toOlap4j(member, operator); * @return A parse tree node of the selection. */ ParseTreeNode visit(); /** * Parent Dimension of the root selection element. * @return A dimension object. */ Dimension getDimension(); /** * Returns the root selection element of this selection. * @return The root metadata object. */ MetadataElement getRootElement(); /** * The selection context includes selections from other dimensions that * help determine the entire context of a selection, so drill down is * possible. * * @return list of selections */ List getSelectionContext(); void addContext(Selection selection); void removeContext(Selection selection); Operator getOperator(); /** * Set the selection operator to use. * @throws IllegalArgumentException if the operator cannot * be used on the root selection member. * @param operator Operator to apply on the selection. */ void setOperator(Operator operator); /** * Defines which selection operators are allowed, relative to * a root member. */ public enum Operator { /** * Only the root member will be selected. */ MEMBER, /** * All members of Level will be selected (LevelSelection only) */ MEMBERS, /** * Only the children of the root member will be selected. * This excludes the root member itself. *

      Implemented via the MDX .Children member property. */ CHILDREN, /** * The root member will be selected along with all it's * children. */ INCLUDE_CHILDREN, /** * Will select the root member along with all it's siblings. *

      Implemented via the MDX .Siblings member property. */ SIBLINGS, /** * Selects the set of the ascendants of a specified member, * including the member itself. *

      Implemented via the MDX Ascendants() function. */ ANCESTORS, /** * Selects the set of the descendants of a specified member, * including the member itself. *

      Implemented via the MDX Descendants() function. */ DESCENDANTS; } } // End Selection.java olap4j-1.0.1.500/src/org/olap4j/query/package.html0000644000175000017500000000034311421322454021274 0ustar drazzibdrazzib Provides an object model for building OLAP queries programmatically (experimental).

      NOTE: This package is experimental. Classes may be renamed or removed in a future release of olap4j. olap4j-1.0.1.500/src/org/olap4j/query/SortOrder.java0000644000175000017500000000324311707255010021603 0ustar drazzibdrazzib/* // $Id: SortOrder.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; /** * Defines in what order to perform sort operations. * @author Luc Boudreau * @version $Id: SortOrder.java 482 2012-01-05 23:27:27Z jhyde $ * @since 0.9.8 */ public enum SortOrder { /** * Ascending sort order. Members of * the same hierarchy are still kept together. */ ASC, /** * Descending sort order. Members of * the same hierarchy are still kept together. */ DESC, /** * Sorts in ascending order, but does not * maintain members of a same hierarchy * together. This is known as a "break * hierarchy ascending sort". */ BASC, /** * Sorts in descending order, but does not * maintain members of a same hierarchy * together. This is known as a "break * hierarchy descending sort". */ BDESC } // End SortOrder.java olap4j-1.0.1.500/src/org/olap4j/query/QueryDimension.java0000644000175000017500000004720111707255010022635 0ustar drazzibdrazzib/* // $Id: QueryDimension.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.OlapException; import org.olap4j.impl.IdentifierParser; import org.olap4j.mdx.IdentifierSegment; import org.olap4j.metadata.*; import java.util.*; /** * Usage of a dimension for an OLAP query. * *

      It references an {@link org.olap4j.metadata.Dimension} and allows the * query creator to manage the member selections for the dimension. * The state of a QueryDimension does not affect the * Dimension object in any way so a single Dimension object * can be referenced by many QueryDimension objects. * * @author jdixon, jhyde, Luc Boudreau * @version $Id: QueryDimension.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 29, 2007 */ public class QueryDimension extends QueryNodeImpl { protected QueryAxis axis; protected final List inclusions = new SelectionList(); protected final List exclusions = new SelectionList(); private final Query query; protected Dimension dimension; private SortOrder sortOrder = null; private HierarchizeMode hierarchizeMode = null; private boolean hierarchyConsistent = false; public QueryDimension(Query query, Dimension dimension) { super(); this.query = query; this.dimension = dimension; } public Query getQuery() { return query; } public void setAxis(QueryAxis axis) { this.axis = axis; } public QueryAxis getAxis() { return axis; } public String getName() { return dimension.getName(); } /** * Selects members and includes them in the query. * *

      This method selects and includes a single member with the * {@link Selection.Operator#MEMBER} operator. * * @param nameParts Name of the member to select and include. * @throws OlapException If no member corresponding to the supplied * name parts could be resolved in the cube. */ public Selection include( List nameParts) throws OlapException { return this.include(Selection.Operator.MEMBER, nameParts); } public Selection createSelection( List nameParts) throws OlapException { return this.createSelection(Selection.Operator.MEMBER, nameParts); } /** * Selects members and includes them in the query. * *

      This method selects and includes a member along with its * relatives, depending on the supplied {@link Selection.Operator} * operator. * * @param operator Selection operator that defines what relatives of the * supplied member name to include along. * @param nameParts Name of the root member to select and include. * @throws OlapException If no member corresponding to the supplied * name parts could be resolved in the cube. */ public Selection include( Selection.Operator operator, List nameParts) throws OlapException { Member member = this.getQuery().getCube().lookupMember(nameParts); if (member == null) { throw new OlapException( "Unable to find a member with name " + nameParts); } return this.include( operator, member); } public Selection createSelection( Selection.Operator operator, List nameParts) throws OlapException { Member member = this.getQuery().getCube().lookupMember(nameParts); if (member == null) { throw new OlapException( "Unable to find a member with name " + nameParts); } return this.createSelection( operator, member); } /** * Selects members and includes them in the query. *

      This method selects and includes a single member with the * {@link Selection.Operator#MEMBER} selection operator. * @param member The member to select and include in the query. */ public Selection include(Member member) { return include(Selection.Operator.MEMBER, member); } public Selection createSelection(Member member) { return createSelection(Selection.Operator.MEMBER, member); } /** * Selects a level and includes it in the query. *

      This method selects and includes a all members of the given * query using the {@link Selection.Operator#MEMBERS} selection operator. * @param level The level to select and include in the query. */ public Selection include(Level level) { if (level.getDimension().equals(this.dimension)) { Selection selection = query.getSelectionFactory().createLevelSelection(level); this.include(selection); return selection; } return null; } /** * Selects members and includes them in the query. *

      This method selects and includes a member along with it's * relatives, depending on the supplied {@link Selection.Operator} * operator. * @param operator Selection operator that defines what relatives of the * supplied member name to include along. * @param member Root member to select and include. */ public Selection createSelection( Selection.Operator operator, Member member) { if (member.getDimension().equals(this.dimension)) { Selection selection = query.getSelectionFactory().createMemberSelection( member, operator); return selection; } return null; } /** * Selects level and includes all members in the query. *

      This method selects and includes all members of a * given Level, using the MEMBERS operator {@link Selection.Operator} * @param level Root level to select and include. */ public Selection createSelection(Level level) { if (level.getDimension().equals(this.dimension)) { Selection selection = query.getSelectionFactory().createLevelSelection(level); return selection; } return null; } /** * Selects members and includes them in the query. *

      This method selects and includes a member along with it's * relatives, depending on the supplied {@link Selection.Operator} * operator. * @param operator Selection operator that defines what relatives of the * supplied member name to include along. * @param member Root member to select and include. */ public Selection include( Selection.Operator operator, Member member) { if (member.getDimension().equals(this.dimension)) { Selection selection = query.getSelectionFactory().createMemberSelection( member, operator); this.include(selection); return selection; } return null; } /** * Includes a selection of members in the query. * @param selection The selection of members to include. */ private void include(Selection selection) { this.getInclusions().add(selection); Integer index = Integer.valueOf( this.getInclusions().indexOf(selection)); this.notifyAdd(selection, index); } /** * Clears the current member inclusions from this query dimension. */ public void clearInclusions() { Map removed = new HashMap(); for (Selection node : this.inclusions) { removed.put( Integer.valueOf(this.inclusions.indexOf(node)), node); ((QueryNodeImpl) node).clearListeners(); } this.inclusions.clear(); this.notifyRemove(removed); } /** * Selects members and excludes them from the query. * *

      This method selects and excludes a single member with the * {@link Selection.Operator#MEMBER} operator. * * @param nameParts Name of the member to select and exclude. * @throws OlapException If no member corresponding to the supplied * name parts could be resolved in the cube. */ public void exclude( List nameParts) throws OlapException { this.exclude(Selection.Operator.MEMBER, nameParts); } /** * Selects members and excludes them from the query. * *

      This method selects and excludes a member along with its * relatives, depending on the supplied {@link Selection.Operator} * operator. * * @param operator Selection operator that defines what relatives of the * supplied member name to exclude along. * @param nameParts Name of the root member to select and exclude. * @throws OlapException If no member corresponding to the supplied * name parts could be resolved in the cube. */ public void exclude( Selection.Operator operator, List nameParts) throws OlapException { Member rootMember = this.getQuery().getCube().lookupMember(nameParts); if (rootMember == null) { throw new OlapException( "Unable to find a member with name " + nameParts); } this.exclude( operator, rootMember); } /** * Selects level members and excludes them from the query. *

      This method selects and excludes members of a level with the * {@link Selection.Operator#MEMBERS} selection operator. * @param level The level to select and exclude from the query. */ public void exclude(Level level) { if (level.getDimension().equals(this.dimension)) { Selection selection = query.getSelectionFactory().createLevelSelection(level); this.exclude(selection); } } /** * Selects members and excludes them from the query. *

      This method selects and excludes a single member with the * {@link Selection.Operator#MEMBER} selection operator. * @param member The member to select and exclude from the query. */ public void exclude(Member member) { exclude(Selection.Operator.MEMBER, member); } /** * Selects members and excludes them from the query. *

      This method selects and excludes a member along with it's * relatives, depending on the supplied {@link Selection.Operator} * operator. * @param operator Selection operator that defines what relatives of the * supplied member name to exclude along. * @param member Root member to select and exclude. */ public void exclude( Selection.Operator operator, Member member) { if (member.getDimension().equals(this.dimension)) { Selection selection = query.getSelectionFactory().createMemberSelection( member, operator); this.exclude(selection); } } /** * Excludes a selection of members from the query. * @param selection The selection of members to exclude. */ private void exclude(Selection selection) { this.getExclusions().add(selection); Integer index = Integer.valueOf( this.getExclusions().indexOf(selection)); this.notifyAdd(selection, index); } /** * Clears the current member inclusions from this query dimension. */ public void clearExclusions() { Map removed = new HashMap(); for (Selection node : this.exclusions) { removed.put( Integer.valueOf(this.exclusions.indexOf(node)), node); ((QueryNodeImpl) node).clearListeners(); } this.exclusions.clear(); this.notifyRemove(removed); } /** * Resolves a selection of members into an actual list * of the root member and it's relatives selected by the Selection object. * @param selection The selection of members to resolve. * @return A list of the actual members selected by the selection object. * @throws OlapException If resolving the selections triggers an exception * while looking up members in the underlying cube. */ public List resolve(Selection selection) throws OlapException { assert selection != null; final Member.TreeOp op; Member.TreeOp secondOp = null; switch (selection.getOperator()) { 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, IdentifierParser.parseIdentifier( selection.getUniqueName())); } catch (Exception e) { throw new OlapException( "Error while resolving selection " + selection.toString(), e); } } /** * Returns a list of the inclusions within this dimension. * *

      Be aware that modifications to this list might * have unpredictable consequences.

      * * @return list of inclusions */ public List getInclusions() { return inclusions; } /** * Returns a list of the exclusions within this dimension. * *

      Be aware that modifications to this list might * have unpredictable consequences.

      * * @return list of exclusions */ public List getExclusions() { return exclusions; } /** * Returns the underlying dimension object onto which * this query dimension is based. *

      Returns a mutable object so operations on it have * unpredictable consequences. * @return The underlying dimension representation. */ public Dimension getDimension() { return dimension; } /** * Forces a change onto which dimension is the current * base of this QueryDimension object. *

      Forcing a change in the duimension assignment has * unpredictable consequences. * @param dimension The new dimension to assign to this * query dimension. */ public void setDimension(Dimension dimension) { this.dimension = dimension; } /** * Sorts the dimension members by name in the * order supplied as a parameter. * @param order The {@link SortOrder} to use. */ public void sort(SortOrder order) { this.sortOrder = order; } /** * Returns the current order in which the * dimension members are sorted. * @return A value of {@link SortOrder} */ public SortOrder getSortOrder() { return this.sortOrder; } /** * Clears the current sorting settings. */ public void clearSort() { this.sortOrder = null; } /** * Returns the current mode of hierarchization, or null * if no hierarchization is currently performed. * *

      This capability is only available when a single dimension is * selected on an axis * * @return Either a hierarchization mode value or null * if no hierarchization is currently performed. */ public HierarchizeMode getHierarchizeMode() { return hierarchizeMode; } /** * Triggers the hierarchization of the included members within this * QueryDimension. * *

      The dimension inclusions will be wrapped in an MDX Hierarchize * function call. * *

      This capability is only available when a single dimension is * selected on an axis. * * @param hierarchizeMode If parents should be included before or after * their children. (Equivalent to the POST/PRE MDX literal for the * Hierarchize() function) * inside the Hierarchize() MDX function call. */ public void setHierarchizeMode(HierarchizeMode hierarchizeMode) { this.hierarchizeMode = hierarchizeMode; } /** * Tells the QueryDimension not to hierarchize its included * selections. * *

      This capability is only available when a single dimension is * selected on an axis. */ public void clearHierarchizeMode() { this.hierarchizeMode = null; } /** * Tells the QueryDimension not to keep a consistent hierarchy * within the inclusions when the mdx is generated. * Only members whose Ancestors are included will be included. * *

      It uses the MDX function FILTER() in combination with * ANCESTOR() to produce a set like:

      * {[Time].[1997]},
      * Filter({{[Time].[Quarter].Members}}, * (Ancestor([Time].CurrentMember, [Time].[Year]) IN {[Time].[1997]})) */ public void setHierarchyConsistent(boolean consistent) { this.hierarchyConsistent = consistent; } /** * Tells the QueryDimension not to keep a consistent hierarchy */ public boolean isHierarchyConsistent() { return this.hierarchyConsistent; } private class SelectionList extends AbstractList { private final List list = new ArrayList(); public Selection get(int index) { return list.get(index); } public int size() { return list.size(); } public Selection set(int index, Selection selection) { return list.set(index, selection); } public void add(int index, Selection selection) { if (this.contains(selection)) { throw new IllegalStateException( "dimension already contains selection"); } list.add(index, selection); } public Selection remove(int index) { return list.remove(index); } } /** * Defines in which way the hierarchize operation * should be performed. */ public static enum HierarchizeMode { /** * Parents are placed before children. */ PRE, /** * Parents are placed after children */ POST } void tearDown() { for (Selection node : this.inclusions) { ((QueryNodeImpl)node).clearListeners(); } for (Selection node : this.exclusions) { ((QueryNodeImpl)node).clearListeners(); } this.inclusions.clear(); this.exclusions.clear(); } } // End QueryDimension.java olap4j-1.0.1.500/src/org/olap4j/query/LevelSelectionImpl.java0000644000175000017500000000752711707255010023430 0ustar drazzibdrazzib/* // $Id: LevelSelectionImpl.java 484 2012-01-05 23:55:56Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.OlapException; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.*; import org.olap4j.metadata.Level.Type; /** * Abstract implementation of {@link Selection}. * * @author pstoellberger * @version $Id: LevelSelectionImpl.java 484 2012-01-05 23:55:56Z jhyde $ * @since Feb 3, 2011 */ class LevelSelectionImpl extends AbstractSelection { protected Level level; public LevelSelectionImpl( Level level, Dimension dimension, Operator operator) { super(dimension, operator); this.level = level; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((level == null) ? 0 : level.getUniqueName().hashCode()); result = prime * result + ((operator == null) ? 0 : operator.hashCode()); result = prime * result + ((selectionContext == null) ? 0 : selectionContext.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof LevelSelectionImpl)) { return false; } LevelSelectionImpl other = (LevelSelectionImpl) obj; if (level == null) { if (other.level != null) { return false; } } else if (!level.getUniqueName().equals( other.level.getUniqueName())) { return false; } if (operator == null) { if (other.operator != null) { return false; } } else if (!operator.equals(other.operator)) { return false; } if (selectionContext == null) { if (other.selectionContext != null) { return false; } } else if (!selectionContext.equals(other.selectionContext)) { return false; } return true; } public MetadataElement getRootElement() { return level; } public ParseTreeNode visit() { // TODO this is a hack for MONDRIAN-929 and needs to be removed again if (level.getLevelType().equals(Type.ALL) && operator.equals(Operator.MEMBERS)) { try { return Olap4jNodeConverter.toOlap4j( level.getHierarchy().getDefaultMember(), Operator.MEMBER); } catch (OlapException e) { e.printStackTrace(); } } return Olap4jNodeConverter.toOlap4j(level, operator); } @Override public void setOperator(Operator operator) { if (!operator.equals(Operator.MEMBERS)) { throw new IllegalArgumentException( "Selections based on a Level have to be of Operator MEMBERS."); } super.setOperator(operator); } } // End LevelSelectionImpl.java olap4j-1.0.1.500/src/org/olap4j/query/Query.java0000644000175000017500000003077411707255010020776 0ustar drazzibdrazzib/* // $Id: Query.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.*; import org.olap4j.mdx.SelectNode; import org.olap4j.metadata.*; import java.sql.SQLException; import java.util.*; import java.util.Map.Entry; /** * Base query model object. * * @author jhyde, jdixon, Luc Boudreau * @version $Id: Query.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 29, 2007 */ public class Query extends QueryNodeImpl { protected final String name; protected Map axes = new HashMap(); protected QueryAxis across; protected QueryAxis down; protected QueryAxis filter; protected QueryAxis unused; protected final Cube cube; protected Map dimensionMap = new HashMap(); /** * Whether or not to select the default hierarchy and default * member on a dimension if no explicit selections were performed. */ protected boolean selectDefaultMembers = true; private final OlapConnection connection; private final SelectionFactory selectionFactory = new SelectionFactory(); /** * Constructs a Query object. * @param name Any arbitrary name to give to this query. * @param cube A Cube object against which to build a query. * @throws SQLException If an error occurs while accessing the * cube's underlying connection. */ public Query(String name, Cube cube) throws SQLException { super(); this.name = name; this.cube = cube; final Catalog catalog = cube.getSchema().getCatalog(); this.connection = catalog.getMetaData().getConnection().unwrap(OlapConnection.class); this.connection.setCatalog(catalog.getName()); this.unused = new QueryAxis(this, null); for (Dimension dimension : cube.getDimensions()) { QueryDimension queryDimension = new QueryDimension( this, dimension); unused.getDimensions().add(queryDimension); dimensionMap.put(queryDimension.getName(), queryDimension); } across = new QueryAxis(this, Axis.COLUMNS); down = new QueryAxis(this, Axis.ROWS); filter = new QueryAxis(this, Axis.FILTER); axes.put(null, unused); axes.put(Axis.COLUMNS, across); axes.put(Axis.ROWS, down); axes.put(Axis.FILTER, filter); } /** * Returns the MDX parse tree behind this Query. The returned object is * generated for each call to this function. Altering the returned * SelectNode object won't affect the query itself. * @return A SelectNode object representing the current query structure. */ public SelectNode getSelect() { return Olap4jNodeConverter.toOlap4j(this); } /** * Returns the underlying cube object that is used to query against. * @return The Olap4j's Cube object. */ public Cube getCube() { return cube; } /** * Returns the Olap4j's Dimension object according to the name * given as a parameter. If no dimension of the given name is found, * a null value will be returned. * @param name The name of the dimension you want the object for. * @return The dimension object, null if no dimension of that * name can be found. */ public QueryDimension getDimension(String name) { return dimensionMap.get(name); } /** * Swaps rows and columns axes. Only applicable if there are two axes. */ public void swapAxes() { // Only applicable if there are two axes - plus filter and unused. if (axes.size() != 4) { throw new IllegalArgumentException(); } List tmpAcross = new ArrayList(); tmpAcross.addAll(across.getDimensions()); List tmpDown = new ArrayList(); tmpDown.addAll(down.getDimensions()); across.getDimensions().clear(); Map acrossChildList = new HashMap(); for (int cpt = 0; cpt < tmpAcross.size();cpt++) { acrossChildList.put(Integer.valueOf(cpt), tmpAcross.get(cpt)); } across.notifyRemove(acrossChildList); down.getDimensions().clear(); Map downChildList = new HashMap(); for (int cpt = 0; cpt < tmpDown.size();cpt++) { downChildList.put(Integer.valueOf(cpt), tmpDown.get(cpt)); } down.notifyRemove(downChildList); across.getDimensions().addAll(tmpDown); across.notifyAdd(downChildList); down.getDimensions().addAll(tmpAcross); down.notifyAdd(acrossChildList); } /** * Returns the query axis for a given axis type. * *

      If you pass axis=null, returns a special axis that is used to hold * all unused hierarchies. (We may change this behavior in future.) * * @param axis Axis type * @return Query axis */ public QueryAxis getAxis(Axis axis) { return this.axes.get(axis); } /** * Returns a map of the current query's axis. *

      Be aware that modifications to this list might * have unpredictable consequences.

      * @return A standard Map object that represents the * current query's axis. */ public Map getAxes() { return axes; } /** * Returns the fictional axis into which all unused dimensions are stored. * All dimensions included in this axis will not be part of the query. * @return The QueryAxis representing dimensions that are currently not * used inside the query. */ public QueryAxis getUnusedAxis() { return unused; } /** * Safely disposes of all underlying objects of this * query. * @param closeConnection Whether or not to call the * {@link OlapConnection#close()} method of the underlying * connection. */ public void tearDown(boolean closeConnection) { for (Entry entry : this.axes.entrySet()) { entry.getValue().tearDown(); } this.axes.clear(); this.clearListeners(); if (closeConnection) { try { this.connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * Safely disposes of all underlying objects of this * query and closes the underlying {@link OlapConnection}. *

      Equivalent of calling Query.tearDown(true). */ public void tearDown() { this.tearDown(true); } /** * Validates the current query structure. If a dimension axis has * been placed on an axis but no selections were performed on it, * the default hierarchy and default member will be selected. This * can be turned off by invoking the * {@link Query#setSelectDefaultMembers(boolean)} method. * @throws OlapException If the query is not valid, an exception * will be thrown and it's message will describe exactly what to fix. */ public void validate() throws OlapException { try { // First, perform default selections if needed. if (this.selectDefaultMembers) { // Perform default selection on the dimensions on the rows axis. for (QueryDimension dimension : this.getAxis(Axis.ROWS) .getDimensions()) { if (dimension.getInclusions().size() == 0) { Member defaultMember = dimension.getDimension() .getDefaultHierarchy().getDefaultMember(); dimension.include(defaultMember); } } // Perform default selection on the // dimensions on the columns axis. for (QueryDimension dimension : this.getAxis(Axis.COLUMNS) .getDimensions()) { if (dimension.getInclusions().size() == 0) { Member defaultMember = dimension.getDimension() .getDefaultHierarchy().getDefaultMember(); dimension.include(defaultMember); } } // Perform default selection on the dimensions // on the filter axis. for (QueryDimension dimension : this.getAxis(Axis.FILTER) .getDimensions()) { if (dimension.getInclusions().size() == 0) { Member defaultMember = dimension.getDimension() .getDefaultHierarchy().getDefaultMember(); dimension.include(defaultMember); } } } // We at least need a dimension on the rows and on the columns axis. if (this.getAxis(Axis.ROWS).getDimensions().size() == 0) { throw new OlapException( "A valid Query requires at least one dimension on the rows axis."); } if (this.getAxis(Axis.COLUMNS).getDimensions().size() == 0) { throw new OlapException( "A valid Query requires at least one dimension on the columns axis."); } // Try to build a select tree. this.getSelect(); } catch (Exception e) { throw new OlapException("Query validation failed.", e); } } /** * Executes the query against the current OlapConnection and returns * a CellSet object representation of the data. * * @return A proper CellSet object that represents the query execution * results. * @throws OlapException If something goes sour, an OlapException will * be thrown to the caller. It could be caused by many things, like * a stale connection. Look at the root cause for more details. */ public CellSet execute() throws OlapException { SelectNode mdx = getSelect(); final Catalog catalog = cube.getSchema().getCatalog(); try { this.connection.setCatalog(catalog.getName()); } catch (SQLException e) { throw new OlapException("Error while executing query", e); } OlapStatement olapStatement = connection.createStatement(); return olapStatement.executeOlapQuery(mdx); } /** * Returns this query's name. There is no guarantee that it is unique * and is set at object instanciation. * @return This query's name. */ public String getName() { return name; } /** * Returns the current locale with which this query is expressed. * @return A standard Locale object. */ public Locale getLocale() { // REVIEW Do queries really support locales? return Locale.getDefault(); } /** * Package restricted method to access this query's selection factory. * Usually used by query dimensions who wants to perform selections. * @return The underlying SelectionFactory implementation. */ SelectionFactory getSelectionFactory() { return selectionFactory; } /** * Behavior setter for a query. By default, if a dimension is placed on * an axis but no selections are made, the default hierarchy and * the default member will be selected when validating the query. * This behavior can be turned off by this setter. * @param selectDefaultMembers Enables or disables the default * member and hierarchy selection upon validation. */ public void setSelectDefaultMembers(boolean selectDefaultMembers) { this.selectDefaultMembers = selectDefaultMembers; } } // End Query.java olap4j-1.0.1.500/src/org/olap4j/query/MemberSelectionImpl.java0000644000175000017500000000660611707255010023565 0ustar drazzibdrazzib/* // $Id: MemberSelectionImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.*; /** * Abstract implementation of {@link Selection}. * * @author jhyde * @version $Id: MemberSelectionImpl.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 30, 2007 */ class MemberSelectionImpl extends AbstractSelection { private Member member; /** * Creates a SelectionImpl. * * @pre operator != null */ public MemberSelectionImpl( Member member, Dimension dimension, Operator operator) { super(dimension, operator); this.member = member; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((member == null) ? 0 : member.getUniqueName().hashCode()); result = prime * result + ((operator == null) ? 0 : operator.hashCode()); result = prime * result + ((selectionContext == null) ? 0 : selectionContext.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof MemberSelectionImpl)) { return false; } MemberSelectionImpl other = (MemberSelectionImpl) obj; if (member == null) { if (other.member != null) { return false; } } else if (!member.getUniqueName().equals( other.member.getUniqueName())) { return false; } if (operator == null) { if (other.operator != null) { return false; } } else if (!operator.equals(other.operator)) { return false; } if (selectionContext == null) { if (other.selectionContext != null) { return false; } } else if (!selectionContext.equals(other.selectionContext)) { return false; } return true; } public MetadataElement getRootElement() { return member; } public ParseTreeNode visit() { return Olap4jNodeConverter.toOlap4j(member, operator); } @Override public void setOperator(Operator operator) { if (operator.equals(Operator.MEMBERS)) { throw new IllegalArgumentException( "Selections based on a Members cannot be of Operator MEMBERS."); } super.setOperator(operator); } } // End MemberSelectionImpl.java olap4j-1.0.1.500/src/org/olap4j/query/QueryEvent.java0000644000175000017500000000760311707255010021773 0ustar drazzibdrazzib/* // $Id: QueryEvent.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import java.util.*; /** * Describes which changes were performed to the query model. * * @author Luc Boudreau * @version $Id: QueryEvent.java 482 2012-01-05 23:27:27Z jhyde $ */ public final class QueryEvent { /** * Describes the nature of the event. */ public static enum Type { /** * Event where one or more children of a QueryNode were removed. */ CHILDREN_REMOVED, /** * Event where one or more nodes were added as children of a QueryNode. */ CHILDREN_ADDED, /** * Event where a Selection object operator was changed. */ SELECTION_CHANGED } private final QueryNode source; private final QueryEvent.Type operation; private final Map children; /** * Creates a QueryEvent with a single child. * * @param operation Even type * @param source Query node that generated this event * @param child Child node */ QueryEvent( QueryEvent.Type operation, QueryNode source, QueryNode child, int index) { this.children = Collections.singletonMap(index, child); this.source = source; this.operation = operation; } /** * Creates a QueryEvent with multiple children. * * @param operation Even type * @param source Query node that generated this event * @param children Child nodes and their indexes within the parent */ QueryEvent( QueryEvent.Type operation, QueryNode source, Map children) { // copy the map, and make immutable this.children = Collections.unmodifiableMap( new HashMap(children)); this.source = source; this.operation = operation; } /** * Creates a QueryEvent with no children. * * @param operation Even type * @param source Query node that generated this event */ QueryEvent( QueryEvent.Type operation, QueryNode source) { this.children = null; this.source = source; this.operation = operation; } /** * Returns the object that generated this event. */ public QueryNode getSource() { return source; } /** * Returns the event type. */ // REVIEW: consider renaming to 'getEventType', or rename enum Type to // Operation. public QueryEvent.Type getOperation() { return operation; } /** * Returns a map of objects affected by the event and * their index in the list of the source children. * *

      If the event is of type {@link QueryEvent.Type#SELECTION_CHANGED}, * this method will return null because the source object was affected * and not the children. */ // REVIEW: 'children' is already plural. Consider renaming to 'getChildren' // or 'getChildNodes'. public Map getChildrens() { return children; } } // End QueryEvent.java olap4j-1.0.1.500/src/org/olap4j/query/QueryAxis.java0000644000175000017500000002753511707255010021624 0ustar drazzibdrazzib/* // $Id: QueryAxis.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.Axis; import org.olap4j.OlapException; import org.olap4j.mdx.IdentifierSegment; import org.olap4j.metadata.Measure; import org.olap4j.metadata.Member; import java.util.*; /** * An axis within an OLAP {@link Query}. * *

      An axis has a location (columns, rows, etc) and has zero or more * dimensions that are placed on it. * * @author jdixon, Luc Boudreau * @version $Id: QueryAxis.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 29, 2007 */ public class QueryAxis extends QueryNodeImpl { protected final List dimensions = new DimensionList(); private final Query query; protected Axis location = null; private boolean nonEmpty; private SortOrder sortOrder = null; private String sortEvaluationLiteral = null; /** * Creates a QueryAxis. * * @param query Query that the axis belongs to * @param location Location of axis (e.g. ROWS, COLUMNS) */ public QueryAxis(Query query, Axis location) { super(); this.query = query; this.location = location; } /** * Returns the location of this QueryAxis in the query; * null if unused. * * @return location of this axis in the query */ public Axis getLocation() { return location; } /** * Returns a list of the dimensions placed on this QueryAxis. * *

      Be aware that modifications to this list might * have unpredictable consequences.

      * * @return list of dimensions */ public List getDimensions() { return dimensions; } /** * Returns the name of this QueryAxis. * * @return the name of this axis, for example "ROWS", "COLUMNS". */ public String getName() { return location.getCaption(query.getLocale()); } /** * Places a QueryDimension object one position before in the * list of current dimensions. Uses a 0 based index. * For example, to place the 5th dimension on the current axis * one position before, one would need to call pullUp(4), * so the dimension would then use axis index 4 and the previous * dimension at that position gets pushed down one position. * @param index The index of the dimension to move up one notch. * It uses a zero based index. */ public void pullUp(int index) { Map removed = new HashMap(); removed.put(Integer.valueOf(index), this.dimensions.get(index)); Map added = new HashMap(); added.put(Integer.valueOf(index - 1), this.dimensions.get(index)); Collections.swap(this.dimensions, index, index - 1); this.notifyRemove(removed); this.notifyAdd(added); } /** * Places a QueryDimension object one position lower in the * list of current dimensions. Uses a 0 based index. * For example, to place the 4th dimension on the current axis * one position lower, one would need to call pushDown(3), * so the dimension would then use axis index 4 and the previous * dimension at that position gets pulled up one position. * @param index The index of the dimension to move down one notch. * It uses a zero based index. */ public void pushDown(int index) { Map removed = new HashMap(); removed.put(Integer.valueOf(index), this.dimensions.get(index)); Map added = new HashMap(); added.put(Integer.valueOf(index + 1), this.dimensions.get(index)); Collections.swap(this.dimensions, index, index + 1); this.notifyRemove(removed); this.notifyAdd(added); } /** * Places a {@link QueryDimension} object on this axis. * @param dimension The {@link QueryDimension} object to add * to this axis. */ public void addDimension(QueryDimension dimension) { this.getDimensions().add(dimension); Integer index = Integer.valueOf( this.getDimensions().indexOf(dimension)); this.notifyAdd(dimension, index); } /** * Places a {@link QueryDimension} object on this axis at * a specific index. * @param dimension The {@link QueryDimension} object to add * to this axis. * @param index The position (0 based) onto which to place * the QueryDimension */ public void addDimension(int index, QueryDimension dimension) { this.getDimensions().add(index, dimension); this.notifyAdd(dimension, index); } /** * Removes a {@link QueryDimension} object on this axis. * @param dimension The {@link QueryDimension} object to remove * from this axis. */ public void removeDimension(QueryDimension dimension) { Integer index = Integer.valueOf( this.getDimensions().indexOf(dimension)); this.getDimensions().remove(dimension); this.notifyRemove(dimension, index); } /** * Returns whether this QueryAxis filters out empty rows. * If true, axis filters out empty rows, and the MDX to evaluate the axis * will be generated with the "NON EMPTY" expression. * * @return Whether this axis should filter out empty rows * * @see #setNonEmpty(boolean) */ public boolean isNonEmpty() { return nonEmpty; } /** * Sets whether this QueryAxis filters out empty rows. * * @param nonEmpty Whether this axis should filter out empty rows * * @see #isNonEmpty() */ public void setNonEmpty(boolean nonEmpty) { this.nonEmpty = nonEmpty; } /** * List of QueryDimension objects. The list is active: when a dimension * is added to the list, it is removed from its previous axis. */ private class DimensionList extends AbstractList { private final List list = new ArrayList(); public QueryDimension get(int index) { return list.get(index); } public int size() { return list.size(); } public QueryDimension set(int index, QueryDimension dimension) { if (dimension.getAxis() != null && dimension.getAxis() != QueryAxis.this) { dimension.getAxis().getDimensions().remove(dimension); } dimension.setAxis(QueryAxis.this); return list.set(index, dimension); } public void add(int index, QueryDimension dimension) { if (this.contains(dimension)) { throw new IllegalStateException( "dimension already on this axis"); } if (dimension.getAxis() != null && dimension.getAxis() != QueryAxis.this) { // careful! potential for loop dimension.getAxis().getDimensions().remove(dimension); } dimension.setAxis(QueryAxis.this); if (index >= list.size()) { list.add(dimension); } else { list.add(index, dimension); } } public QueryDimension remove(int index) { QueryDimension dimension = list.remove(index); dimension.setAxis(null); return dimension; } } void tearDown() { for (QueryDimension node : this.getDimensions()) { node.tearDown(); } this.clearListeners(); this.getDimensions().clear(); } /** *

      Sorts the axis according to the supplied order. The sort evaluation * expression will be the default member of the default hierarchy of * the dimension named "Measures". * @param order The {@link SortOrder} to apply * @throws OlapException If an error occurs while resolving * the default measure of the underlying cube. */ public void sort(SortOrder order) throws OlapException { sort( order, query.getCube().getDimensions().get("Measures") .getDefaultHierarchy().getDefaultMember()); } /** * Sorts the axis according to the supplied order * and member unique name. * *

      Using this method will try to resolve the supplied name * parts from the underlying cube and find the corresponding * member. This member will then be passed as a sort evaluation * expression. * * @param order The {@link SortOrder} in which to * sort the axis. * @param nameParts The unique name parts of the sort * evaluation expression. * @throws OlapException If the supplied member cannot be resolved * with {@link org.olap4j.metadata.Cube#lookupMember(java.util.List)} */ public void sort(SortOrder order, List nameParts) throws OlapException { assert order != null; assert nameParts != null; Member member = query.getCube().lookupMember(nameParts); if (member == null) { throw new OlapException("Cannot find member."); } sort(order, member); } /** *

      Sorts the axis according to the supplied order * and member. *

      This method is most commonly called by passing * it a {@link Measure}. * @param order The {@link SortOrder} in which to * sort the axis. * @param member The member that will be used as a sort * evaluation expression. */ public void sort(SortOrder order, Member member) { assert order != null; assert member != null; sort(order, member.getUniqueName()); } /** *

      Sorts the axis according to the supplied order * and evaluation expression. *

      The string value passed as the sortEvaluationLitteral * parameter will be used literally as a sort evaluator. * @param order The {@link SortOrder} in which to * sort the axis. * @param sortEvaluationLiteral The literal expression that * will be used to sort against. */ public void sort(SortOrder order, String sortEvaluationLiteral) { assert order != null; assert sortEvaluationLiteral != null; this.sortOrder = order; this.sortEvaluationLiteral = sortEvaluationLiteral; } /** * Clears the sort parameters from this axis. */ public void clearSort() { this.sortEvaluationLiteral = null; this.sortOrder = null; } /** * Returns the current sort order in which this * axis will be sorted. Might return null of none * is currently specified. * @return The {@link SortOrder} */ public SortOrder getSortOrder() { return this.sortOrder; } /** * Returns the current sort evaluation expression, * or null if none are currently defined. * @return The string literal that will be used in the * MDX Order() function. */ public String getSortIdentifierNodeName() { return sortEvaluationLiteral; } } // End QueryAxis.java olap4j-1.0.1.500/src/org/olap4j/query/QueryNodeListener.java0000644000175000017500000000377711707255010023315 0ustar drazzibdrazzib/* // $Id: QueryNodeListener.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; /** * Objects that want to be notified of changes to the Query Model structure * have to implement this interface. * * @author Luc Boudreau * @version $Id: QueryNodeListener.java 482 2012-01-05 23:27:27Z jhyde $ */ public interface QueryNodeListener { /** * Invoked when one or more children of a QueryNode are removed * from its list. * * @param event Describes in detail the actual event that just happened. */ public void childrenRemoved(QueryEvent event); /** * Invoked when one or more children are added to a QueryNode * list of children. * * @param event Describes in detail the actual event that just happened. */ public void childrenAdded(QueryEvent event); /** * Invoked when a selection operator has changed. This does not mean * that a Selection object was either added or removed from a Dimension, * it only means that its operator value was modified. * * @param event Describes in detail the actual event that just happened. * @see org.olap4j.query.Selection **/ public void selectionChanged(QueryEvent event); } // End QueryNodeListener.java olap4j-1.0.1.500/src/org/olap4j/query/SelectionFactory.java0000644000175000017500000000330211707255010023131 0ustar drazzibdrazzib/* // $Id: SelectionFactory.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.metadata.Level; import org.olap4j.metadata.Member; /** * Contains factory methods for creating implementations of {@link Selection}. * *

      Created using {@link Query#getSelectionFactory()}. * * @author jhyde * @version $Id: SelectionFactory.java 482 2012-01-05 23:27:27Z jhyde $ * @since May 30, 2007 */ class SelectionFactory { Selection createMemberSelection( Member member, Selection.Operator operator) { return new MemberSelectionImpl( member, member.getDimension(), operator); } Selection createLevelSelection(Level level) { return new LevelSelectionImpl( level, level.getDimension(), Selection.Operator.MEMBERS); } } // End SelectionFactory.java olap4j-1.0.1.500/src/org/olap4j/query/AbstractSelection.java0000644000175000017500000000436311707255010023275 0ustar drazzibdrazzib/* // $Id: AbstractSelection.java 483 2012-01-05 23:43:18Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.metadata.Dimension; import java.util.ArrayList; import java.util.List; /** * Abstract implementation of a selection. * @author LBoudreau * @version $Id: AbstractSelection.java 483 2012-01-05 23:43:18Z jhyde $ */ abstract class AbstractSelection extends QueryNodeImpl implements Selection { Operator operator; Dimension dimension; List selectionContext; public AbstractSelection( Dimension dimension, Operator operator) { this.dimension = dimension; this.operator = operator; } public Dimension getDimension() { return dimension; } public Operator getOperator() { return operator; } public void setOperator(Operator operator) { assert operator != null; this.operator = operator; notifyChange(this,-1); } void tearDown() { } public List getSelectionContext() { return selectionContext; } public void addContext(Selection selection) { if (selectionContext == null) { selectionContext = new ArrayList(); } selectionContext.add(selection); } public void removeContext(Selection selection) { selectionContext.remove(selection); } public String getUniqueName() { return getRootElement().getUniqueName(); } } // End AbstractSelection.java olap4j-1.0.1.500/src/org/olap4j/query/QueryNodeImpl.java0000644000175000017500000001315611707255010022421 0ustar drazzibdrazzib/* // $Id: QueryNodeImpl.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import java.util.*; /** * Abstract implementation of QueryNode that * implements operations to support listeners. * * @author Luc Boudreau * @version $Id: QueryNodeImpl.java 482 2012-01-05 23:27:27Z jhyde $ */ abstract class QueryNodeImpl implements QueryNode { private final List listeners = new ArrayList(); public void addQueryNodeListener(QueryNodeListener l) { this.listeners.add(l); } public void removeQueryNodeListener(QueryNodeListener l) { this.listeners.remove(l); } /** * Subclasses should call this helper method to * notify its listeners that a child was added. * * @param child Child that was added * @param index The index at which it was added */ protected void notifyAdd(QueryNode child, int index) { assert child != null; QueryEvent event = new QueryEvent( QueryEvent.Type.CHILDREN_ADDED, this, child, index); notifyAddInternal(event); } /** * Subclasses should call this helper method to * notify it's listeners that children were added. * * @param children A map of indexes and children QueryNode * objects that were added */ protected void notifyAdd(Map children) { assert children != null; QueryEvent event = new QueryEvent( QueryEvent.Type.CHILDREN_ADDED, this, children); notifyAddInternal(event); } private void notifyAddInternal(QueryEvent event) { // Must count backwards to prevent an exception // if a child removes itself from the listeners list // while this call is active. for (int cpt = this.listeners.size() - 1; cpt >= 0; cpt--) { this.listeners.get(cpt).childrenAdded(event); } } /** * Subclasses should call this helper method to * notify its listeners that a child was removed. * * @param child Child that was removed * @param index Index of child */ protected void notifyRemove(QueryNode child, int index) { assert child != null; QueryEvent event = new QueryEvent( QueryEvent.Type.CHILDREN_REMOVED, this, child, index); notifyRemoveInternal(event); } /** * Subclasses should call this helper method to * notify its listeners that children were added. * * @param children A map of indexes and children QueryNode * objects that were removed */ protected void notifyRemove(Map children) { assert children != null; QueryEvent event = new QueryEvent( QueryEvent.Type.CHILDREN_REMOVED, this, children); notifyRemoveInternal(event); } private void notifyRemoveInternal(QueryEvent event) { // Must count backwards to prevent an exception // if a child removes itself from the listeners list // while this call is active. for (int cpt = this.listeners.size() - 1; cpt >= 0; cpt--) { this.listeners.get(cpt).childrenRemoved(event); } } /** * Subclasses should call this helper method to * notify its listeners that a child selection * object has a new operator value. * * @param child Child that was updated * @param index The index of the child among its siblings */ protected void notifyChange(QueryNode child, int index) { assert child != null; QueryEvent event = new QueryEvent( QueryEvent.Type.SELECTION_CHANGED, this, child, index); notifyChangeInternal(event); } /** * Subclasses should call this helper method to * notify its listeners that children selections * object has a new operator value. * * @param children A map of indexes and children QueryNode * objects that were updated */ protected void notifyChange(Map children) { assert children != null; QueryEvent event = new QueryEvent( QueryEvent.Type.SELECTION_CHANGED, this, children); notifyChangeInternal(event); } private void notifyChangeInternal(QueryEvent event) { // Must count backwards to prevent an exception // if a child removes itself from the listeners list // while this call is active. for (int cpt = this.listeners.size() - 1; cpt >= 0; cpt--) { this.listeners.get(cpt).selectionChanged(event); } } void clearListeners() { this.listeners.clear(); } abstract void tearDown(); } // End QueryNodeImpl.java olap4j-1.0.1.500/src/org/olap4j/query/Olap4jNodeConverter.java0000644000175000017500000006131111707255010023507 0ustar drazzibdrazzib/* // $Id: Olap4jNodeConverter.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; import org.olap4j.Axis; import org.olap4j.mdx.*; import org.olap4j.metadata.Level; import org.olap4j.metadata.Member; import java.util.*; /** * Utility class to convert a Query object to a SelectNode. */ abstract class Olap4jNodeConverter { public static 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)); AxisNode filterAxis = null; if (query.getAxes().containsKey(Axis.FILTER)) { final QueryAxis axis = query.getAxes().get(Axis.FILTER); if (!axis.dimensions.isEmpty()) { filterAxis = toOlap4j(axis); } } return new SelectNode( null, withList, toOlap4j(axisList), new CubeNode( null, query.getCube()), filterAxis, list); } private static CallNode generateSetCall(ParseTreeNode... args) { return new CallNode( null, "{}", Syntax.Braces, args); } private static CallNode generateListSetCall(List cnodes) { return new CallNode( null, "{}", Syntax.Braces, cnodes); } private static CallNode generateListTupleCall(List cnodes) { return new CallNode( null, "()", Syntax.Parentheses, cnodes); } protected static CallNode generateCrossJoin(List selections) { ParseTreeNode sel1 = selections.remove(0); if (sel1 instanceof MemberNode) { sel1 = generateSetCall(sel1); } if (selections.size() == 1) { ParseTreeNode sel2 = selections.get(0); if (sel2 instanceof MemberNode) { sel2 = generateSetCall(sel2); } return new CallNode( null, "CrossJoin", Syntax.Function, sel1, sel2); } else { return new CallNode( null, "CrossJoin", Syntax.Function, sel1, generateCrossJoin(selections)); } } protected static CallNode generateUnion(List> unions) { if (unions.size() > 2) { List first = unions.remove(0); return new CallNode( null, "Union", Syntax.Function, generateCrossJoin(first), generateUnion(unions)); } else { return new CallNode( null, "Union", Syntax.Function, generateCrossJoin(unions.get(0)), generateCrossJoin(unions.get(1))); } } protected static CallNode generateHierarchizeUnion( List> unions) { return new CallNode( null, "Hierarchize", Syntax.Function, generateUnion(unions)); } /** * Algorithm:

        *
      • generate all combinations of dimension groups *
      • skip the selection if has a context *
      • for all the selections with context, resolve them last *
      • union all combinations *
      */ private static void generateUnionsRecursively( QueryAxis axis, int dim, List curr, List> unions, List selsWithContext, List> contextUnions) { ParseTreeNode exceptSet = null; QueryDimension qDim = axis.getDimensions().get(dim); List exclusionSelections = qDim.getExclusions(); List exclusionNodes = new ArrayList(); // Check if any exclusions are selected for this dimension // and convert them to a list of nodes and then later a set for (Selection exclusion : exclusionSelections) { exclusionNodes.add(toOlap4j(exclusion)); } if (exclusionNodes.size() > 0) { exceptSet = generateListSetCall(exclusionNodes); } for (Selection sel : qDim.getInclusions()) { ParseTreeNode selectionNode = toOlap4j(sel); // If a the querydimension should return only hierarchy // consistent results, generate a filter that checks // inclusions for ancestors in higher levels if (qDim.isHierarchyConsistent() && qDim.getInclusions().size() > 1) { Integer currentDepth = null; if (sel.getRootElement() instanceof Member) { currentDepth = ((Member)sel.getRootElement()).getDepth(); } else if (sel.getRootElement() instanceof Level) { currentDepth = ((Level)sel.getRootElement()).getDepth(); } selectionNode = toHierarchyConsistentNode(selectionNode, currentDepth, qDim); } // If a sort Order was specified for this dimension // apply it for this inclusion if (qDim.getSortOrder() != null) { CallNode currentMemberNode = new CallNode( null, "CurrentMember", Syntax.Property, new DimensionNode(null, sel.getDimension())); CallNode currentMemberNameNode = new CallNode( null, "Name", Syntax.Property, currentMemberNode); selectionNode = new CallNode( null, "Order", Syntax.Function, generateSetCall(selectionNode), currentMemberNameNode, LiteralNode.createSymbol( null, qDim.getSortOrder().name())); } // If there are exlclusions wrap the ordered selection // in an Except() function if (exceptSet != null) { selectionNode = new CallNode( null, "Except", Syntax.Function, generateSetCall(selectionNode), exceptSet); } if (sel.getSelectionContext() != null && sel.getSelectionContext().size() > 0) { // selections that have a context are treated // differently than the rest of the MDX generation if (!selsWithContext.contains(sel)) { ArrayList sels = new ArrayList(); for (int i = 0; i < axis.getDimensions().size(); i++) { if (dim == i) { sels.add(selectionNode); } else { // return the selections in the correct // dimensional order QueryDimension dimension = axis.getDimensions().get(i); boolean found = false; for (Selection selection : sel.getSelectionContext()) { if (selection.getDimension().equals( dimension.getDimension())) { sels.add(toOlap4j(selection)); found = true; } } if (!found) { // add the first selection of the dimension if (dimension.getInclusions().size() > 0) { sels.add(toOlap4j( dimension.getInclusions().get(0))); } } } } contextUnions.add(sels); selsWithContext.add(sel); } } else { List ncurr = new ArrayList(); if (curr != null) { ncurr.addAll(curr); } ncurr.add(selectionNode); if (dim == axis.getDimensions().size() - 1) { // last dimension unions.add(ncurr); } else { generateUnionsRecursively( axis, dim + 1, ncurr, unions, selsWithContext, contextUnions); } } } } /* * This method merges the selections into a single * MDX axis selection. Right now we do a simple * crossjoin. * It might return null if there are no dimensions placed on the axis. */ private static AxisNode toOlap4j(QueryAxis axis) { CallNode callNode = null; int numDimensions = axis.getDimensions().size(); if (numDimensions == 0) { return null; } else if (numDimensions == 1) { QueryDimension dimension = axis.getDimensions().get(0); List members = toOlap4j(dimension); callNode = generateListSetCall(members); } else { // generate union sets of selections in each dimension List> unions = new ArrayList>(); List selsWithContext = new ArrayList(); List> contextUnions = new ArrayList>(); generateUnionsRecursively( axis, 0, null, unions, selsWithContext, contextUnions); unions.addAll(contextUnions); if (unions.size() > 1) { callNode = generateHierarchizeUnion(unions); } else { callNode = generateCrossJoin(unions.get(0)); } } // We might need to sort the whole axis. ParseTreeNode sortedNode = null; if (axis.getSortOrder() != null) { LiteralNode evaluatorNode = LiteralNode.createSymbol( null, axis.getSortIdentifierNodeName()); sortedNode = new CallNode( null, "Order", Syntax.Function, callNode, evaluatorNode, LiteralNode.createSymbol( null, axis.getSortOrder().name())); } else { sortedNode = callNode; } return new AxisNode( null, axis.isNonEmpty(), axis.getLocation(), new ArrayList(), sortedNode); } private static List toOlap4j(QueryDimension dimension) { // Let's build a first list of included members. List includeList = new ArrayList(); Map> levelNodes = new HashMap>(); for (Selection selection : dimension.getInclusions()) { ParseTreeNode selectionNode = toOlap4j(selection); // If a the querydimension should return only hierarchy // consistent results, generate a filter that checks // inclusions for ancestors in higher levels if (dimension.isHierarchyConsistent() && dimension.getInclusions().size() > 1) { Integer curdepth = 0; if (selection.getRootElement() instanceof Member) { curdepth = ((Member)selection.getRootElement()).getDepth(); } else if (selection.getRootElement() instanceof Level) { curdepth = ((Level)selection.getRootElement()).getDepth(); } if (levelNodes.get(curdepth) != null) { levelNodes.get(curdepth).add(selectionNode); } else { List nodes = new ArrayList(); nodes.add(selectionNode); levelNodes.put(curdepth, nodes); } } else { includeList.add(selectionNode); } } if (dimension.isHierarchyConsistent() && dimension.getInclusions().size() > 1) { Integer levelDepths[] = levelNodes.keySet() .toArray(new Integer[levelNodes.keySet().size()]); Arrays.sort(levelDepths); for (Integer depth : levelDepths) { ParseTreeNode levelNode = generateListSetCall(levelNodes.get(depth)); levelNode = toHierarchyConsistentNode(levelNode, depth, dimension); includeList.add(levelNode); } } // If a sort order was specified, we need to wrap the inclusions in an // Order() mdx function. List orderedList = new ArrayList(); if (dimension.getSortOrder() != null) { CallNode currentMemberNode = new CallNode( null, "CurrentMember", Syntax.Property, new DimensionNode(null, dimension.getDimension())); CallNode currentMemberNameNode = new CallNode( null, "Name", Syntax.Property, currentMemberNode); orderedList.add( new CallNode( null, "Order", Syntax.Function, generateListSetCall(includeList), currentMemberNameNode, LiteralNode.createSymbol( null, dimension.getSortOrder().name()))); } else { orderedList.addAll(includeList); } // We're not done yet. We might have to exclude members from the // inclusion, so we might have to wrap the list in a mdx Except() // function call. List listWithExclusions = new ArrayList(); if (dimension.getExclusions().size() > 0) { List excludedMembers = new ArrayList(); for (Selection selection : dimension.getExclusions()) { excludedMembers.add(toOlap4j(selection)); } listWithExclusions.add( new CallNode( null, "Except", Syntax.Function, generateListSetCall(orderedList), generateListSetCall(excludedMembers))); } else { listWithExclusions.addAll(orderedList); } // Do we need to wrap it all in a Hierarchize function? List listWithHierarchy = new ArrayList(); if (dimension.getHierarchizeMode() != null) { CallNode hierarchyNode; // There are two modes available, PRE and POST. if (dimension.getHierarchizeMode().equals( QueryDimension.HierarchizeMode.PRE)) { // In pre mode, we don't add the "POST" literal. hierarchyNode = new CallNode( null, "Hierarchize", Syntax.Function, generateListSetCall(listWithExclusions)); } else if (dimension.getHierarchizeMode().equals( QueryDimension.HierarchizeMode.POST)) { hierarchyNode = new CallNode( null, "Hierarchize", Syntax.Function, generateListSetCall(listWithExclusions), LiteralNode.createSymbol( null, dimension.getHierarchizeMode().name())); } else { throw new RuntimeException("Missing value handler."); } listWithHierarchy.add(hierarchyNode); } else { listWithHierarchy.addAll(listWithExclusions); } return listWithHierarchy; } private static ParseTreeNode toOlap4j(Selection selection) { try { return selection.visit(); } catch (Exception e) { e.printStackTrace(); } return null; } static 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; } static ParseTreeNode toOlap4j( Level level, Selection.Operator oper) { ParseTreeNode node = null; try { switch (oper) { case MEMBERS: node = new CallNode( null, "Members", Syntax.Property, new LevelNode(null, level)); break; default: System.out.println("NOT IMPLEMENTED: " + oper); } } catch (Exception e) { e.printStackTrace(); } return node; } private static List toOlap4j(List axes) { final ArrayList axisList = new ArrayList(); for (QueryAxis axis : axes) { AxisNode axisNode = toOlap4j(axis); if (axisNode != null) { axisList.add(toOlap4j(axis)); } } return axisList; } private static ParseTreeNode toHierarchyConsistentNode( ParseTreeNode selectionNode, Integer maxDepth, QueryDimension qDim) { // If a the querydimension should return only hierarchy // consistent results, generate a filter that checks // inclusions for ancestors in higher levels if (qDim.getInclusions().size() > 1) { Map levels = new HashMap(); for (Selection s : qDim.getInclusions()) { if (s.getRootElement() instanceof Member) { Integer d = ((Member)s.getRootElement()).getDepth(); if (!levels.containsKey(d)) { Level lvl = ((Member)s.getRootElement()).getLevel(); levels.put(d, lvl); } } else if (s.getRootElement() instanceof Level) { Integer d = ((Level)s.getRootElement()).getDepth(); if (!levels.containsKey(d)) { Level lvl = ((Level)s.getRootElement()); levels.put(d, lvl); } } } Integer levelDepths[] = levels.keySet() .toArray(new Integer[levels.keySet().size()]); Arrays.sort(levelDepths); List inConditions = new ArrayList(); for (Integer i = 0; i < levelDepths.length - 1; i++) { Level currentLevel = levels.get(levelDepths[i]); if (levelDepths[i] < maxDepth && currentLevel.getLevelType() != Level.Type.ALL) { CallNode currentMemberNode = new CallNode( null, "CurrentMember", Syntax.Property, new HierarchyNode( null, currentLevel.getHierarchy())); CallNode ancestorNode = new CallNode( null, "Ancestor", Syntax.Function, currentMemberNode, new LevelNode(null, currentLevel)); List ancestorList = new ArrayList(); for (Selection anc : qDim.getInclusions()) { if (anc.getRootElement() instanceof Member) { Level l = ((Member)anc.getRootElement()).getLevel(); if (l.equals(levels.get(levelDepths[i]))) { ancestorList.add(anc.visit()); } } } if (ancestorList.size() > 0) { CallNode ancestorSet = generateListSetCall(ancestorList); CallNode inClause = new CallNode( null, "IN", Syntax.Infix, ancestorNode, ancestorSet); inConditions.add(inClause); } } } if (inConditions.size() > 0) { CallNode chainedIn = inConditions.get(0); if (inConditions.size() > 1) { for (int c = 1;c < inConditions.size();c++) { chainedIn = new CallNode( null, "AND", Syntax.Infix, chainedIn, inConditions.get(c)); } } return new CallNode( null, "Filter", Syntax.Function, generateSetCall(selectionNode), chainedIn); } } return selectionNode; } } // End Olap4jNodeConverter.java olap4j-1.0.1.500/src/org/olap4j/query/QueryNode.java0000644000175000017500000000324211707255010021572 0ustar drazzibdrazzib/* // $Id: QueryNode.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.query; /** * Describes what methods a Query Node must implement * in order to support listeners. Olap4j's query model * provides an abstract implementation of interface. * * @author Luc Boudreau */ interface QueryNode { /** * Registers a new listener for a QueryNode. * @param l The new listener object, implementation of QueryNodeListener * @see org.olap4j.query.QueryNodeListener */ public void addQueryNodeListener(QueryNodeListener l); /** * De-registers a new listener for a QueryNode. * If the listener object passed as a parameter was not registered, * the method will return silently. * @param l The listener object to de-register. * @see org.olap4j.query.QueryNodeListener */ public void removeQueryNodeListener(QueryNodeListener l); } // End QueryNode.java olap4j-1.0.1.500/src/org/olap4j/CellSetMetaData.java0000644000175000017500000000526011707255012021452 0ustar drazzibdrazzib/* // $Id: CellSetMetaData.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.metadata.*; import java.sql.ResultSetMetaData; /** * An object that can be used to get information about the axes * and cells in a CellSet object. * *

      The following code fragment creates the CellSet object cs, * creates the CellSetMetaData object csmd, and uses csmd * to find out how many axes cs has and the name of the cube. * *

      *
       * CellSet cs = stmt.executeOlapQuery(
       *     "SELECT {[Measures].[Unit Sales] ON COLUMNS,\n" +
       *     "   Crossjoin([Time].Children, [Store].Children) ON ROWS\n" +
       *     "FROM [Sales]");
       * CellSetMetaData csmd = cs.getMetaData();
       * int numberOfAxes = csmd.getAxesMetaData().size();
       * String cubeName = csmd.getCube().getName();
       * 
      *
      * * @author jhyde * @version $Id: CellSetMetaData.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 23, 2006 */ public interface CellSetMetaData extends ResultSetMetaData, OlapWrapper { /** * Returns a list of Property objects which each Cell may have. * * @return list of cell properties */ NamedList getCellProperties(); /** * Returns the Cube which was referenced in this statement. * * @return cube referenced in this statement */ Cube getCube(); /** * Returns a list of CellSetAxisMetaData describing each result axis. * * @return list of metadata describing each result axis */ NamedList getAxesMetaData(); /** * Returns a CellSetAxisMetaData describing the filter axis. Never returns * null; if the MDX statement contains no WHERE clause, the description of * the filter contains no hierarchies. * * @return metadata describing filter axis */ CellSetAxisMetaData getFilterAxisMetaData(); } // End CellSetMetaData.java olap4j-1.0.1.500/src/org/olap4j/OlapParameterMetaData.java0000644000175000017500000000453511707255012022657 0ustar drazzibdrazzib/* // $Id: OlapParameterMetaData.java 482 2012-01-05 23:27:27Z jhyde $ // // Licensed to Julian Hyde under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Julian Hyde licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j; import org.olap4j.type.Type; import java.sql.ParameterMetaData; /** * Extension to {@link ParameterMetaData} for parameters of OLAP statements. * *

      Chief differences: *

        *
      • An OLAP statement parameter has a name. *
      • An OLAP statement parameter may be a member. If this is the case, * the {@link #getParameterType(int)} method returns * {@link java.sql.Types#OTHER}. *
      • An additional method {@link #getParameterOlapType(int)} provides extra * type information; in particular, the hierarchy that a member parameter * belongs to. *
      * *

      Parameters to an OLAP statement must have default values, and therefore * it is not necessary to set every parameter. * * @author jhyde * @version $Id: OlapParameterMetaData.java 482 2012-01-05 23:27:27Z jhyde $ * @since Oct 12, 2006 */ public interface OlapParameterMetaData extends ParameterMetaData { /** * Returns the name of this parameter. * * @param param the first parameter is 1, the second is 2, ... * @return parameter name * @exception OlapException if a database access error occurs */ String getParameterName(int param) throws OlapException; /** * Retrieves the designated parameter's OLAP type. * * @param param the first parameter is 1, the second is 2, ... * @return OLAP type * @exception OlapException if a database access error occurs */ Type getParameterOlapType(int param) throws OlapException; } // End OlapParameterMetaData.java olap4j-1.0.1.500/subfloor.xml0000644000175000017500000021210711707255014015463 0ustar drazzibdrazzib ------------------------------------------------------------------------------- subfloor.xml provides tasks needed to perform a project build. It is typically not used directly but imported by each project's build.xml file. The build.xml file can override tasks when customization is required. MAIN TARGETS ============ * clean / clean-all : remove all artifacts of the build, clean-all adds the removal of any library or jar dependencies downloaded as part of the build * resolve : download/refresh library or jar dependencies needed for the build (uses Apache IVY) * compile : run javac on the project's source * jar : creates a jar file * dist : creates all project distributables * test : runs JUnit tests from your project's test source SPECIAL TARGETS ============ * publish-local : builds a jar for your project and registers it with the local artifact repository isolated to your machine at $HOME/.ivy2/local. Further executions of the the resolve target by this or other projects will find your published jar. * ivy-clean* : this family of targets helps reset your IVY environment in the event that you are having difficulty resolving dependencies TYPICAL TARGET SEQUENCE ============ * clean-all resolve dist : a good start to build all project distributables from scratch. Note that jar dependencies will not be downloaded unless you explicitly run the resolve target. We made the resolution and retrieval completely discretionary since there are many situations in which you will not want to get or refresh dependencies, e.g. if you are offline with no Internet access. In such case, you could just run "dist" if the set of jars you already have are sufficient. olap4j-1.0.1.500/CHANGES.txt0000644000175000017500000002116711713756776014745 0ustar drazzibdrazzib# $Id: CHANGES.txt 491 2012-01-24 17:02:14Z lucboudreau $ ############################################################################### # Olap4j 1.0.1 This release is a maintenance release and maintains backwards compatibility with version 1.0.0. The license under which olap4j is distributed has changed starting with this release. Olap4j is now distributed in accordance to the Apache License Version 2.0. Among other notable changes, this version introduces support for JDBC 4.1. * New Features / Improvements - Added support for Java 7 / JDBC 4.1. - XMLA now supports locales. - TCK now tests the roles and access controls. * XMLA Bug Fixes - Fixed bug 848534. Virtual cubes are now returned as part of Schema.getCubes(). - Fixed issues with the experimental Query Model. - Fixes an issue with SAP BW where the XMLA driver would scan through all the available databases/catalogs/schemas, causing access control exceptions. - Added the ability to pass server specific properties as part of the XMLA's PropertyList payload. - The XmlaDriver now exposes a public constructor to prevent errors in Sun's JDBC implementation. # Olap4j 1.0.0 Although this file was not kept up to date since a while, we intend to change this starting with version 1.0.0. :) Olap4j 1.0.0 brings changes to the top of the metadata hierarchy, changes in the driver specification, along with the removal of all APIs which were marked for deprecation prior to 1.0.0. * Metadata changes Version 1.0.0 introduces a new object at the top of the OlapDatabaseMetaData, namely the Database object. The database was an implicit member; we have decided to turn it into a first class object of the hierarchy. Catalogs have been modified to reflect this new parent. OlapConnections now have methods to explore the Databases, Catalogs and Schemas on a server. * Driver specification changes OlapConnections must now be bound unto a database, a catalog and a schema before being able to resolve cubes and execute queries. Reference implementations have been modified to reflect the correct behavior, as was the TCK. New methods were added to OlapConnection in order to change the connection binding and obtain lists of available Databases, Catalogs and Schemas. Olap4j is now split into five Java libraries. * olap4j.jar The core API * olap4j-xmla.jar The XML/A driver for olap4j. * olap4j-tck.jar TCK classes. * olap4j-jdk14.jar Java 1.4 compatible release. Contains the core API and XML/A driver. * olap4j-sources.jar Java source files. =============================================================================== # Changes to olap4j since olap4j-0.9.3. Summary of changes between olap4j-0.9.3 and olap4j-0.9.4-svn072: * olap4j now has an XMLA driver. Tested against mondrian's XMLA driver, it should also work against other XMLA drivers such as Microsoft Analysis Services. * olap4j's mondrian driver is now part of the mondrian release. Look for it in mondrian-3.0 onwards. * More tests, numerous bug-fixes. API changes: * Arguments to AxisNode constructor re-ordered. * Hierarchy.getDefaultMEmber() now throws OlapException. * Cube.getMeasures() returns members sorted by ordinal. * Added constructor for IdentifierNode which takes a list (convenient for calling with the result from IdentifierNode.parseIdentifier). ------------------------------------------------------------------------ r72 | jhyde | 2008-02-05 11:46:03 -0800 (Tue, 05 Feb 2008) | 1 line Up olap4j version; remove jars required by mondrian driver (now that it lives under mondrian). ------------------------------------------------------------------------ r71 | jhyde | 2008-02-05 11:37:23 -0800 (Tue, 05 Feb 2008) | 1 line XMLA driver now reads member corresponding to each measure, so that it can sort by ordinal. ------------------------------------------------------------------------ r70 | jhyde | 2008-02-04 16:22:15 -0800 (Mon, 04 Feb 2008) | 1 line Cube.getMeasures() returns members sorted by ordinal. ------------------------------------------------------------------------ r69 | jhyde | 2008-02-02 15:28:59 -0800 (Sat, 02 Feb 2008) | 1 line Switch order of parameters to AxisNode (it's easier to write code if the bulky expression comes last). Fix 'jar' build on windows. Push up memory for unit test (in-process XMLA test is hungry). ------------------------------------------------------------------------ r68 | jhyde | 2008-01-31 23:07:41 -0800 (Thu, 31 Jan 2008) | 1 line XMLA driver: add member cache; call MDSCHEMA_MEMBERS with multiple unique-names. Hierarchy.getDefaultMember() now throws OlapException. XmlaTester caches connections. ------------------------------------------------------------------------ r67 | jhyde | 2008-01-23 23:42:35 -0800 (Wed, 23 Jan 2008) | 1 line XMLA driver: when constructing metadata request XML, encode restriction values ------------------------------------------------------------------------ r66 | jhyde | 2008-01-23 23:21:25 -0800 (Wed, 23 Jan 2008) | 1 line Add constructor for IdentifierNode which takes a list (convenient for calling with the result from IdentifierNode.parseIdentifier); Test case for building MDX parse tree programmatically and executing as query. ------------------------------------------------------------------------ r65 | jhyde | 2008-01-23 21:14:58 -0800 (Wed, 23 Jan 2008) | 1 line Add support for Basic Authentication to XMLA driver (contributed by Luc Boudreau); add Base64 utilities (needed for Basic Authentication); fix MetadataTest for additional functions just added to mondrian. ------------------------------------------------------------------------ r64 | jhyde | 2008-01-21 06:13:36 -0800 (Mon, 21 Jan 2008) | 1 line Oops ------------------------------------------------------------------------ r63 | jhyde | 2008-01-21 06:12:55 -0800 (Mon, 21 Jan 2008) | 1 line Remove unused mondrian import ------------------------------------------------------------------------ r62 | jhyde | 2008-01-12 18:18:47 -0800 (Sat, 12 Jan 2008) | 1 line Fix XMLA driver for calculated members defined in query; and make hierarchies and members returned for the slicer consistent between XMLA and mondrian drivers. ------------------------------------------------------------------------ r61 | jhyde | 2008-01-10 11:20:01 -0800 (Thu, 10 Jan 2008) | 1 line Fix typo in javadoc ------------------------------------------------------------------------ r60 | jhyde | 2008-01-10 01:25:49 -0800 (Thu, 10 Jan 2008) | 1 line Clarify what the slicer axis contains if the query has no WHERE clause; clarify Cell.getFormattedValue() if the value is NULL; and add testcase for query with no slicer. ------------------------------------------------------------------------ r59 | jhyde | 2008-01-09 21:35:55 -0800 (Wed, 09 Jan 2008) | 1 line Move olap4j driver for mondrian to mondrian code base. ------------------------------------------------------------------------ r58 | jhyde | 2008-01-09 00:34:03 -0800 (Wed, 09 Jan 2008) | 1 line Enable keyword substitution for some source files. ------------------------------------------------------------------------ r57 | jhyde | 2008-01-09 00:31:56 -0800 (Wed, 09 Jan 2008) | 1 line XMLA driver now uses HTTP POST (some server's don't support GET) ------------------------------------------------------------------------ r56 | jhyde | 2008-01-06 12:34:57 -0800 (Sun, 06 Jan 2008) | 1 line Fix metadata test now mondrian has more functions ------------------------------------------------------------------------ r55 | jhyde | 2007-12-21 15:55:30 -0800 (Fri, 21 Dec 2007) | 1 line Update MetadataTest now mondrian has 2 extra functions; fix drill-through test for Derby's JDBC driver weirdness. ------------------------------------------------------------------------ r54 | jhyde | 2007-12-18 14:11:57 -0800 (Tue, 18 Dec 2007) | 1 line Fix code examples in functional spec, and improve a few javadoc comments. ResultSet returned from Cell.drillThrough() now closes its connection and statement on close, thereby fixing a connection leak. ------------------------------------------------------------------------ r53 | jhyde | 2007-12-13 17:07:28 -0800 (Thu, 13 Dec 2007) | 1 line Oops: fix for JDK 1.5, and fix typo in ant classpath; update web home page for 0.9.3. ------------------------------------------------------------------------ r52 | jhyde | 2007-12-13 15:15:53 -0800 (Thu, 13 Dec 2007) | 1 line Major progress on XMLA driver. All tests pass for XMLA driver (running against mondrian in-process, but nevertheless sending and receiving SOAP requests) and still pass for mondrian driver. ------------------------------------------------------------------------ # End CHANGES.txt olap4j-1.0.1.500/ivy-jdk14.xml0000644000175000017500000000503011707255014015345 0ustar drazzibdrazzib olap4j is an open Java API for OLAP. Think of it like JDBC, but 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.