public class PhysicalSchema {
	
	public String schema;
	public String dataSource;
	
	public List<DimensionTable> dimensions;
	public List<AggregateTable> aggregates;
	
	private DbSpec dbSpec;
	private DbSchema dbSchema;

	public void index(CatalogDefinition catalogDefinition) throws OlapException {
		
		dbSpec = new DbSpec();
		dbSchema = dbSpec.addSchema(schema);
		
		for(DimensionTable t : dimensions){
			t.index(dbSchema);
		}
		
		for(AggregateTable t : aggregates){
			t.index(dbSchema, catalogDefinition);
		}
		
		
	}

	public DbSpec getDbSpec() {
		return dbSpec;
	}

	public DbSchema getDbSchema() {
		return dbSchema;
	}
	
	public DimensionTable findDimensionTable(String name){
		for(DimensionTable dt : dimensions){
			if(dt.table.equals(name))
				return dt;
		}
		return null;
	}
	
	public DimensionTable findDimensionTable(Dimension dimension){
		
		for(AggregateTable at : aggregates){
			for(TableJoin join: at.joins){
				if(join.dimension.equals(dimension.getName()))
					return findDimensionTable(join.table);
			}
		}
		
		return null;
	}

} public class TableJoin {

	public String dimension, table, key;

	private DbJoin dbJoin;
	private DimensionTable dimensionTable;
	private DbColumn foreign_key;
	
	public DbJoin getDbJoin() {
		return dbJoin;
	}

	public void setDbJoin(DbJoin dbJoin) {
		this.dbJoin = dbJoin;
	}

	public DimensionTable getDimensionTable() {
		return dimensionTable;
	}

	public void setDimensionTable(DimensionTable dimensionTable) {
		this.dimensionTable = dimensionTable;
	}

	public DbColumn getForeign_key() {
		return foreign_key;
	}

	public void setForeign_key(DbColumn foreign_key) {
		this.foreign_key = foreign_key;
	}
	
} public class ServerCellSet implements CellSet {

	private OlapStatement olapStatement;
	private boolean closed;
	private ArrayList<CellSetAxis> axes = new ArrayList<CellSetAxis>();
	private CellSetAxis filterAxis;
	private Cube cube;
	private Map< String, Cell  > cells = new HashMap< String, Cell>();
	
	public ServerCellSet(OlapStatement olapStatement, Cube cube) {
		this.olapStatement = olapStatement;
		this.cube = cube;
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		return null;
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		return false;
	}

	@Override
	public boolean next() throws SQLException {
		return false;
	}

	@Override
	public void close() throws SQLException {
		this.closed = true;
	}

	@Override
	public boolean wasNull() throws SQLException {
		return false;
	}

	@Override
	public String getString(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public boolean getBoolean(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public byte getByte(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public short getShort(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public int getInt(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public long getLong(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public float getFloat(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public double getDouble(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public BigDecimal getBigDecimal(int columnIndex, int scale)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public byte[] getBytes(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Date getDate(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Time getTime(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Timestamp getTimestamp(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public InputStream getAsciiStream(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public InputStream getUnicodeStream(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public InputStream getBinaryStream(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public String getString(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public boolean getBoolean(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public byte getByte(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public short getShort(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public int getInt(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public long getLong(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public float getFloat(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public double getDouble(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public BigDecimal getBigDecimal(String columnLabel, int scale)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public byte[] getBytes(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Date getDate(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Time getTime(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Timestamp getTimestamp(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public InputStream getAsciiStream(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public InputStream getUnicodeStream(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public InputStream getBinaryStream(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public SQLWarning getWarnings() throws SQLException {
		return null;
	}

	@Override
	public void clearWarnings() throws SQLException {
	}

	@Override
	public String getCursorName() throws SQLException {
		return null;
	}


	@Override
	public Object getObject(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Object getObject(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public int findColumn(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Reader getCharacterStream(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Reader getCharacterStream(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public boolean isBeforeFirst() throws SQLException {
		return false;
	}

	@Override
	public boolean isAfterLast() throws SQLException {
		return false;
	}

	@Override
	public boolean isFirst() throws SQLException {
		return false;
	}

	@Override
	public boolean isLast() throws SQLException {
		return false;
	}

	@Override
	public void beforeFirst() throws SQLException {
	}

	@Override
	public void afterLast() throws SQLException {
	}

	@Override
	public boolean first() throws SQLException {
		return false;
	}

	@Override
	public boolean last() throws SQLException {
		return false;
	}

	@Override
	public int getRow() throws SQLException {
		return 0;
	}

	@Override
	public boolean absolute(int row) throws SQLException {
		return false;
	}

	@Override
	public boolean relative(int rows) throws SQLException {
		return false;
	}

	@Override
	public boolean previous() throws SQLException {
		return false;
	}

	@Override
	public void setFetchDirection(int direction) throws SQLException {
		olapStatement.setFetchDirection(direction);
	}

	@Override
	public int getFetchDirection() throws SQLException {
		return olapStatement.getFetchDirection();
	}

	@Override
	public void setFetchSize(int rows) throws SQLException {
		olapStatement.setFetchSize(rows);
	}

	@Override
	public int getFetchSize() throws SQLException {
		return olapStatement.getFetchSize();
	}

	@Override
	public int getType() throws SQLException {
		return 0;
	}

	@Override
	public int getConcurrency() throws SQLException {
		return 0;
	}

	@Override
	public boolean rowUpdated() throws SQLException {
		return false;
	}

	@Override
	public boolean rowInserted() throws SQLException {
		return false;
	}

	@Override
	public boolean rowDeleted() throws SQLException {
		return false;
	}

	@Override
	public void updateNull(int columnIndex) throws SQLException {
	}

	@Override
	public void updateBoolean(int columnIndex, boolean x) throws SQLException {
	}

	@Override
	public void updateByte(int columnIndex, byte x) throws SQLException {
	}

	@Override
	public void updateShort(int columnIndex, short x) throws SQLException {
	}

	@Override
	public void updateInt(int columnIndex, int x) throws SQLException {
	}

	@Override
	public void updateLong(int columnIndex, long x) throws SQLException {
	}

	@Override
	public void updateFloat(int columnIndex, float x) throws SQLException {
	}

	@Override
	public void updateDouble(int columnIndex, double x) throws SQLException {
	}

	@Override
	public void updateBigDecimal(int columnIndex, BigDecimal x)
			throws SQLException {
	}

	@Override
	public void updateString(int columnIndex, String x) throws SQLException {
	}

	@Override
	public void updateBytes(int columnIndex, byte[] x) throws SQLException {
	}

	@Override
	public void updateDate(int columnIndex, Date x) throws SQLException {
	}

	@Override
	public void updateTime(int columnIndex, Time x) throws SQLException {
	}

	@Override
	public void updateTimestamp(int columnIndex, Timestamp x)
			throws SQLException {
	}

	@Override
	public void updateAsciiStream(int columnIndex, InputStream x, int length)
			throws SQLException {
	}

	@Override
	public void updateBinaryStream(int columnIndex, InputStream x, int length)
			throws SQLException {
	}

	@Override
	public void updateCharacterStream(int columnIndex, Reader x, int length)
			throws SQLException {
	}

	@Override
	public void updateObject(int columnIndex, Object x, int scaleOrLength)
			throws SQLException {
	}

	@Override
	public void updateObject(int columnIndex, Object x) throws SQLException {
	}

	@Override
	public void updateNull(String columnLabel) throws SQLException {
	}

	@Override
	public void updateBoolean(String columnLabel, boolean x)
			throws SQLException {
	}

	@Override
	public void updateByte(String columnLabel, byte x) throws SQLException {
	}

	@Override
	public void updateShort(String columnLabel, short x) throws SQLException {
	}

	@Override
	public void updateInt(String columnLabel, int x) throws SQLException {
	}

	@Override
	public void updateLong(String columnLabel, long x) throws SQLException {
	}

	@Override
	public void updateFloat(String columnLabel, float x) throws SQLException {
	}

	@Override
	public void updateDouble(String columnLabel, double x) throws SQLException {
	}

	@Override
	public void updateBigDecimal(String columnLabel, BigDecimal x)
			throws SQLException {
	}

	@Override
	public void updateString(String columnLabel, String x) throws SQLException {
	}

	@Override
	public void updateBytes(String columnLabel, byte[] x) throws SQLException {
	}

	@Override
	public void updateDate(String columnLabel, Date x) throws SQLException {
	}

	@Override
	public void updateTime(String columnLabel, Time x) throws SQLException {
	}

	@Override
	public void updateTimestamp(String columnLabel, Timestamp x)
			throws SQLException {
	}

	@Override
	public void updateAsciiStream(String columnLabel, InputStream x, int length)
			throws SQLException {
	}

	@Override
	public void updateBinaryStream(String columnLabel, InputStream x, int length)
			throws SQLException {
	}

	@Override
	public void updateCharacterStream(String columnLabel, Reader reader,
			int length) throws SQLException {
	}

	@Override
	public void updateObject(String columnLabel, Object x, int scaleOrLength)
			throws SQLException {
	}

	@Override
	public void updateObject(String columnLabel, Object x) throws SQLException {
	}

	@Override
	public void insertRow() throws SQLException {
	}

	@Override
	public void updateRow() throws SQLException {
	}

	@Override
	public void deleteRow() throws SQLException {
	}

	@Override
	public void refreshRow() throws SQLException {
	}

	@Override
	public void cancelRowUpdates() throws SQLException {
	}

	@Override
	public void moveToInsertRow() throws SQLException {
	}

	@Override
	public void moveToCurrentRow() throws SQLException {
	}

	@Override
	public Object getObject(int columnIndex, Map<String, Class<?>> map)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Ref getRef(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Blob getBlob(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Clob getClob(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Array getArray(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Object getObject(String columnLabel, Map<String, Class<?>> map)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Ref getRef(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Blob getBlob(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Clob getClob(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Array getArray(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Date getDate(int columnIndex, Calendar cal) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Date getDate(String columnLabel, Calendar cal) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Time getTime(int columnIndex, Calendar cal) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Time getTime(String columnLabel, Calendar cal) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Timestamp getTimestamp(int columnIndex, Calendar cal)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Timestamp getTimestamp(String columnLabel, Calendar cal)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public URL getURL(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public URL getURL(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateRef(int columnIndex, Ref x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateRef(String columnLabel, Ref x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBlob(int columnIndex, Blob x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBlob(String columnLabel, Blob x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateClob(int columnIndex, Clob x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateClob(String columnLabel, Clob x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateArray(int columnIndex, Array x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateArray(String columnLabel, Array x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public RowId getRowId(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public RowId getRowId(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateRowId(int columnIndex, RowId x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateRowId(String columnLabel, RowId x) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public int getHoldability() throws SQLException {
		return 0;
	}

	@Override
	public boolean isClosed() throws SQLException {
		return closed;
	}

	@Override
	public void updateNString(int columnIndex, String nString)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNString(String columnLabel, String nString)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNClob(String columnLabel, NClob nClob)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public NClob getNClob(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public NClob getNClob(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public SQLXML getSQLXML(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public SQLXML getSQLXML(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateSQLXML(int columnIndex, SQLXML xmlObject)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateSQLXML(String columnLabel, SQLXML xmlObject)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public String getNString(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public String getNString(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Reader getNCharacterStream(int columnIndex) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public Reader getNCharacterStream(String columnLabel) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNCharacterStream(int columnIndex, Reader x, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNCharacterStream(String columnLabel, Reader reader,
			long length) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateAsciiStream(int columnIndex, InputStream x, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBinaryStream(int columnIndex, InputStream x, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateCharacterStream(int columnIndex, Reader x, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateAsciiStream(String columnLabel, InputStream x, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBinaryStream(String columnLabel, InputStream x,
			long length) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateCharacterStream(String columnLabel, Reader reader,
			long length) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBlob(int columnIndex, InputStream inputStream, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBlob(String columnLabel, InputStream inputStream,
			long length) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateClob(int columnIndex, Reader reader, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateClob(String columnLabel, Reader reader, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNClob(int columnIndex, Reader reader, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNClob(String columnLabel, Reader reader, long length)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNCharacterStream(int columnIndex, Reader x)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNCharacterStream(String columnLabel, Reader reader)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateAsciiStream(int columnIndex, InputStream x)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBinaryStream(int columnIndex, InputStream x)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateCharacterStream(int columnIndex, Reader x)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateAsciiStream(String columnLabel, InputStream x)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBinaryStream(String columnLabel, InputStream x)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateCharacterStream(String columnLabel, Reader reader)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBlob(int columnIndex, InputStream inputStream)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateBlob(String columnLabel, InputStream inputStream)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateClob(int columnIndex, Reader reader) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateClob(String columnLabel, Reader reader)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNClob(int columnIndex, Reader reader) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public void updateNClob(String columnLabel, Reader reader)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public <T> T getObject(String columnLabel, Class<T> type)
			throws SQLException {
		throw new UnsupportedOperationException("Unsupported operation for OLAP cell set");
	}

	@Override
	public List<CellSetAxis> getAxes() {
		return axes;
	}

	@Override
	public CellSetAxis getFilterAxis() {
		return filterAxis;
	}

	@Override
	public Cell getCell(List<Integer> coordinates) {
		String skey = getKeyFromInts(coordinates);
		Cell cell = cells.get(skey);
		if(cell==null){
			cell = new ServerCell(this, coordinates, null, null);	
			cells.put(skey, cell);
		}
		return cell;
	}
	
	
	private String getKeyFromInts(List<Integer> coordinates){
		StringBuffer sb = new StringBuffer();
		for(Integer c : coordinates){
			sb.append(c).append('.');
		}
		return sb.toString();
	}

	@Override
	public Cell getCell(int ordinal) {
		return getCell( ordinalToCoordinates(ordinal) );
	}

	@Override
	public Cell getCell(Position... positions) {
		List<Integer> coordinates = new ArrayList<Integer>(axes.size());
		
		for(int i=0; i < axes.size(); i++){
			CellSetAxis axis = axes.get(i);
			int coord = axis.getPositions().indexOf(positions[i]);
			if(coord<0)
				return null;
			coordinates.set(i, coord);
		}
		
		return getCell(coordinates);
	}

	@Override
	public List<Integer> ordinalToCoordinates(int ordinal) {
		
		List<Integer> coordinates = new ArrayList<Integer>( axes.size() );
		
		
		List<Integer> factors = new ArrayList<Integer>( axes.size() );
		int factor = 1;
		for(int i=0; i< axes.size();i++){
			factors.set(i, factor);
			factor *= axes.get(i).getPositionCount();
		}
		
		int residual = ordinal;
		
		for(int i=axes.size()-1; i >= 0 && residual>=0 ; i--){
			
			int coord = residual / factors.get(i);						
			residual -= factors.get(i) * coord;		
			coordinates.set(i, coord);
		}
		

		return coordinates;
	}

	@Override
	public int coordinatesToOrdinal(List<Integer> coordinates) {		
		int ordinal = 0;		
		for(int i=axes.size()-1; i >= 0 && ordinal>=0 ; i--){			
			CellSetAxis axis = axes.get(i);
			ordinal += coordinates.get(i) + axis.getPositionCount() * ordinal; 
			
		}		
		return ordinal;
	}

	@Override
	public OlapStatement getStatement() throws SQLException {
		return olapStatement;
	}
	

	
	public Cell addCell(Integer[] integers, Number value, DecimalFormat format) {		
		List<Integer> positions = Arrays.asList(integers);
		ServerCell cell = new ServerCell(this, positions, value, format);
		String skey = getKeyFromInts(positions);
		cells.put(skey, cell);
		return cell;
		
	}

	
	@Override
	public CellSetMetaData getMetaData() throws OlapException {
		return new CellSetMetaData(){

			@Override
			public int getColumnCount() throws SQLException {				
				return axes.get(0).getPositionCount();
			}

			@Override
			public boolean isAutoIncrement(int column) throws SQLException {
				return false;
			}

			@Override
			public boolean isCaseSensitive(int column) throws SQLException {
				return false;
			}

			@Override
			public boolean isSearchable(int column) throws SQLException {
				return false;
			}

			@Override
			public boolean isCurrency(int column) throws SQLException {
				return false;
			}

			@Override
			public int isNullable(int column) throws SQLException {
				return columnNullable;
			}

			@Override
			public boolean isSigned(int column) throws SQLException {
				return false;
			}

			@Override
			public int getColumnDisplaySize(int column) throws SQLException {
				return 10;
			}

			@Override
			public String getColumnLabel(int column) throws SQLException {
				return axes.get(0).getPositions().get(column).toString();
			}

			@Override
			public String getColumnName(int column) throws SQLException {
				return getColumnLabel(column);
			}

			@Override
			public String getSchemaName(int column) throws SQLException {
				return getCube().getSchema().getName();
			}

			@Override
			public int getPrecision(int column) throws SQLException {
				return 0;
			}

			@Override
			public int getScale(int column) throws SQLException {
				return 0;
			}

			@Override
			public String getTableName(int column) throws SQLException {
				return getCube().getName();
			}

			@Override
			public String getCatalogName(int column) throws SQLException {
				return getCube().getSchema().getCatalog().getName();
			}

			@Override
			public int getColumnType(int column) throws SQLException {
				return 0;
			}

			@Override
			public String getColumnTypeName(int column) throws SQLException {
				return null;
			}

			@Override
			public boolean isReadOnly(int column) throws SQLException {
				return true;
			}

			@Override
			public boolean isWritable(int column) throws SQLException {
				return false;
			}

			@Override
			public boolean isDefinitelyWritable(int column) throws SQLException {
				return false;
			}

			@Override
			public String getColumnClassName(int column) throws SQLException {
				return null;
			}

			@Override
			public <T> T unwrap(Class<T> iface) throws SQLException {
				return null;
			}

			@Override
			public boolean isWrapperFor(Class<?> iface) throws SQLException {
				return false;
			}

			@Override
			public NamedList<Property> getCellProperties() {
				// TODO Auto-generated method stub
				return null;
			}

			@Override
			public Cube getCube() {
				return cube;
			}

			@Override
			public NamedList<CellSetAxisMetaData> getAxesMetaData() {
				return MetadataUtils.cellSetNamedList(axes);
			}
			

			@Override
			public CellSetAxisMetaData getFilterAxisMetaData() {
				return filterAxis==null ? null : filterAxis.getAxisMetaData();
			}
			
		};
	}

	public void setAxis(ServerCellSetAxis axis) {
		
		if(axis.getAxisOrdinal().isFilter()){
			this.filterAxis = axis;
		}else{
			axes.add(axis);
			Collections.sort(axes, new Comparator<CellSetAxis>() {

				@Override
				public int compare(CellSetAxis o1, CellSetAxis o2) {
					if(o1.getAxisOrdinal().axisOrdinal()>o2.getAxisOrdinal().axisOrdinal()){
						return 1;
					}else if(o1.getAxisOrdinal().axisOrdinal()<o2.getAxisOrdinal().axisOrdinal()){
						return -1;
					}else{
						return 0;
					}
				}
			});
		}
		
		
	}



	
} public class ServerLevel implements Level {

	private ServerHierarchy hierarchy;
	private NamedElement definition;
	private int depth;
	
	protected ServerLevel(ServerHierarchy hierarchy, NamedElement def, int depth){
		this.hierarchy = hierarchy;
		this.definition = def;
		this.depth = depth;
	}
	
	
	@Override
	public String getName() {
		return definition.name;
	}

	@Override
	public String getUniqueName() {
		return hierarchy.getUniqueName() +".["+definition.name+"]";
	}

	@Override
	public String getCaption() {
		return definition.caption;
	}

	@Override
	public String getDescription() {
		return definition.caption;
	}

	@Override
	public boolean isVisible() {
		return true;
	}

	@Override
	public int getDepth() {
		return depth;
	}

	@Override
	public Hierarchy getHierarchy() {
		return hierarchy;
	}

	@Override
	public Dimension getDimension() {
		return hierarchy.getDimension();
	}

	@Override
	public Type getLevelType() {
		return Type.REGULAR;
	}

	@Override
	public boolean isCalculated() {
		return false;
	}

	@Override
	public NamedList<Property> getProperties() {
		return Olap4jUtil.emptyNamedList();
	}

	@Override
	public List<Member> getMembers() throws OlapException {
		ServerDimension dim = (ServerDimension) getDimension();		
		MemberQuery query = new MemberQuery(dim.getServerSchema().getCatalog(), this);
		return query.getMembers();
	}

	@Override
	public int getCardinality() {
		return 0;
	}
} public class ServerMeasure implements Measure {

	private CubeMeasureDefinition definition;
	private Dimension measureDimension;
	private DecimalFormat format;
	
	public ServerMeasure(Dimension measureDimension, CubeMeasureDefinition def) {
		this.definition = def;
		this.measureDimension = measureDimension;
		this.format = def.format==null ? new DecimalFormat("#,##0") : new DecimalFormat(def.format);
	}

	@Override
	public NamedList<? extends Member> getChildMembers() throws OlapException {
		return Olap4jUtil.emptyNamedList();
	}

	@Override
	public int getChildMemberCount() throws OlapException {
		return 0;
	}

	@Override
	public Member getParentMember() {
		return null;
	}

	@Override
	public Level getLevel() {
		return measureDimension.getDefaultHierarchy().getLevels().get(0);
	}

	@Override
	public Hierarchy getHierarchy() {
		return measureDimension.getDefaultHierarchy();
	}

	@Override
	public Dimension getDimension() {
		return measureDimension;
	}

	@Override
	public Type getMemberType() {
		return Type.MEASURE;
	}

	@Override
	public boolean isAll() {
		return false;
	}

	@Override
	public boolean isChildOrEqualTo(Member member) {
		return member==this;
	}

	@Override
	public boolean isCalculated() {
		return false;
	}

	@Override
	public int getSolveOrder() {
		return 0;
	}

	@Override
	public ParseTreeNode getExpression() {
		return null;
	}

	@Override
	public List<Member> getAncestorMembers() {
		return Collections.emptyList();
	}

	@Override
	public boolean isCalculatedInQuery() {
		return false;
	}

	@Override
	public Object getPropertyValue(Property property) throws OlapException {
		if(property==Property.StandardMemberProperty.$visible){
			return new Boolean(isVisible());
		}else if(property==Property.StandardMemberProperty.CHILDREN_CARDINALITY){
			return 0;
		}else if(property==Property.StandardCellProperty.DATATYPE){
			return definition.datatype;
		}else if(property==Property.StandardMemberProperty.MEMBER_UNIQUE_NAME){
			return getUniqueName();
		}else if(property==Property.StandardMemberProperty.MEMBER_CAPTION){
			return getCaption();
		}else if(property==Property.StandardMemberProperty.LEVEL_UNIQUE_NAME){
			return getLevel().getUniqueName();
		}else if(property==Property.StandardMemberProperty.LEVEL_NUMBER){
			return getLevel().getDepth();
		}else{
			return null;
		}
		
	}

	@Override
	public String getPropertyFormattedValue(Property property)
			throws OlapException {
		throw new UnsupportedOperationException("getPropertyFormattedValue");
	}

	@Override
	public void setProperty(Property property, Object value)
			throws OlapException {
		throw new UnsupportedOperationException("setProperty");
	}

	@Override
	public NamedList<Property> getProperties() {
		return Olap4jUtil.emptyNamedList();
	}

	@Override
	public int getOrdinal() {
		return 0;
	}

	@Override
	public boolean isHidden() {
		return false;
	}

	@Override
	public int getDepth() {
		return 0;
	}

	@Override
	public Member getDataMember() {
		throw new UnsupportedOperationException("getDataMember");
	}

	@Override
	public String getName() {
		return definition.name;
	}

	@Override
	public String getUniqueName() {
		return "["+ measureDimension.getName() + "].["+ definition.name +"]";
	}

	@Override
	public String getCaption() {
		return definition.caption;
	}

	@Override
	public String getDescription() {
		return definition.caption;
	}

	@Override
	public Aggregator getAggregator() {
		return Aggregator.valueOf(definition.aggregator);
	}

	@Override
	public Datatype getDatatype() {
		return Datatype.valueOf(definition.datatype);
	}

	@Override
	public boolean isVisible() {
		return true;
	}

	public DecimalFormat getFormat() {
		return format;
	}

} public class LevelMemberSet {
	
	private Level level;
	
	private ParseTreeNode node;
	private OlapOp function;
	private List<Member> members = new ArrayList<Member>();
	private Map<String, Member> map = new HashMap<String, Member>();
	
	private Sorter sorter;
	private int topLimit;
	
	public LevelMemberSet(Level level, ParseTreeNode node, OlapOp function) {
		this.level = level;
		this.node = node;
		this.function = function;
	}

	public LevelMemberSet(Member member, ParseTreeNode node, OlapOp function) {		
		this.level = member.getLevel();
		this.node = node;
		this.function = function;
		members.add(member);		
	}

	public LevelMemberSet(ParseTreeNode node, OlapOp function) {
		this.node = node;
		this.function = function;
	}

	public Level getLevel() {
		return level;
	}
	
	public boolean isMeasure(){
		return level.getDimension() instanceof ServerMeasureDimension;
	}

	public ParseTreeNode getNode() {
		return node;
	}

	public List<Member> getMembers() {
		return members;
	}

		
	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer(level.getUniqueName());
		
		if(!members.isEmpty()){
			sb.append(" with ").append(members.size()).append(" member(s): [");
			for(Member m: members){
				if(m!=members.get(0))
					sb.append(",");
				sb.append(m.getName());
			}
			sb.append("]");
		}
		
		sb.append(" node: ");
		sb.append(ParseUtils.toString(node));

		return sb.toString();
	}

	public OlapOp getFunction() {
		return function;
	}

	public Member findMember(String key, String name) {
		
		Member m = map.get(key);
		if(m!=null)
			return m;
		
		if(topLimit>0 && members.size()>=topLimit)
			return null;
		
		LevelMember member = new LevelMember(level, key, name, members.size());
		members.add(member);
		map.put(key, member);
		
		return member;
	}

	public void setFunction(OlapOp function) {
		this.function = function;
	}

	public Sorter getSorter() {
		return sorter;
	}

	public void setSorter(Sorter sorter) {
		this.sorter = sorter;
	}

	public int getTopLimit() {
		return topLimit;
	}

	public void setTopLimit(int topLimit) {
		this.topLimit = topLimit;
	}
	
	
	
} public class ResultAxis extends ServerCellSetAxis {

	private List<LevelMemberSet> layers;
	private Map<List<Member>, Position> member_map = new HashMap<List<Member>, Position>();
	private List<Position> positions = new ArrayList<Position>();
	
	public ResultAxis(CellSet cellSet, AxisNode axisNode) throws OlapException {
		super(cellSet, axisNode.getAxis());		
		this.layers = OlapFunctionFactory.INSTANCE.function( axisNode.getExpression(), cellSet.getMetaData().getCube()).memberSet();
	}

	@Override
	public List<Position> getPositions() {
		return positions;
	}

	@Override
	protected List<Hierarchy> getHierarchies() {
		List<Hierarchy> hierarchies = new ArrayList<Hierarchy>();

		for(LevelMemberSet layer : layers){
			Hierarchy h = layer.getLevel().getHierarchy();
			if(!hierarchies.contains(h))
				hierarchies.add(h);
		}
		
		return hierarchies;
	}



	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer(getAxisMetaData().getAxisOrdinal().name());
		
		sb.append(" with ").append(layers.size()).append(" layer(s): ");
		for(LevelMemberSet set: layers){
			sb.append("\n");
			sb.append(set.toString());
		}
		
		return sb.toString();
	}

	public List<LevelMemberSet> getLayers() {
		return layers;
	}


	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set<ServerMeasure> collectAllUsedMeasures() throws OlapException{
		
		Set measures = new HashSet();
		for(LevelMemberSet layer : layers){
			if(layer.isMeasure()){
				measures.addAll(layer.getMembers());
			}
			measures.addAll(layer.getFunction().getAllMeasuresUsed());
		}
		
		return measures;
		
	}
	
	public Set<ServerDimension> collectAllUsedDimensions(){
		Set<ServerDimension> dims = new HashSet<ServerDimension>();
		for(LevelMemberSet layer : layers){
			if(!layer.isMeasure()){
				dims.add((ServerDimension) layer.getLevel().getDimension());
			}
			
		}
		
		return dims;		
	}

	public int positionOrdinal(final List<Member> members) {
		
		Position p = member_map.get(members);
		 
		if(p==null){
			final int ordinal = positions.size();
			p = new Position(){

				@Override
				public List<Member> getMembers() {
					return members;
				}

				@Override
				public int getOrdinal() {				
					return ordinal;
				}
				
			};
			member_map.put(members, p);
			positions.add(p);
		}
		
		return p.getOrdinal();
		
	}
	
	
	
} public interface OlapOp {

	public abstract List<LevelMemberSet> memberSet( ) throws OlapException ;

	public abstract SetSubquery query(TableMapping mapping, LevelMemberSet layer) throws OlapException;

	public abstract Collection<ServerMeasure> getAllMeasuresUsed() throws OlapException;
	
} public class LevelMapping {
	public TableJoin join;
	public DimensionTable table;
	public TableColumn name_column;
	public String name_alias;
		
	public TableColumn key_column;
	public String key_alias;
		
	public TableColumn order_column;
} public class MeasureMapping {
	public ServerMeasure measure;
	public TableMeasure column;
	public String alias;
}
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.olap.server.database.physical.PhysicalSchema;
import org.olap.server.database.physical.TableJoin;
import org.olap.server.driver.ServerCellSet;
import org.olap.server.driver.metadata.ServerLevel;
import org.olap.server.driver.metadata.ServerMeasure;
import org.olap.server.processor.LevelMemberSet;
import org.olap.server.processor.ResultAxis;
import org.olap.server.processor.functions.OlapOp;
import org.olap.server.processor.sql.TableMapping.LevelMapping;
import org.olap.server.processor.sql.TableMapping.MeasureMapping;
import org.olap4j.OlapException;
import org.olap4j.metadata.Member;
import com.healthmarketscience.sqlbuilder.Condition;
import com.healthmarketscience.sqlbuilder.SelectQuery;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;

	
	public void generateQuery() throws OlapException{
		
		sql = new SelectQuery();
		
		this.mapping = TableMapping.mapToDatabase(schema, resultAxes, filterAxis);
		
		log.debug("SelectQuery using table: "+mapping.getAggregate().table);
		
		buildColumns();
		
		buildSubQueries();
		
		
		for(TableJoin join : joins){
			sql.addJoins(SelectQuery.JoinType.INNER, join.getDbJoin());
		}
		
		if(!groupings.isEmpty()){
			sql.addGroupings(groupings.toArray(new DbColumn[0]));
		}
		
		for(Condition c: conditions)
			sql.addCondition(c);

		for(Condition c: having_conditions)
			sql.addHaving(c);

		addSorters();
		
		
	}


	protected void addSorters() {
		
		for(ResultAxis axis : resultAxes){
			
			List<Sorter> axisSorters = new ArrayList<Sorter>();
			
			boolean breaks_hierarchy = false;
			for(LevelMemberSet layer : axis.getLayers()){
				if(layer.getSorter()!=null){
					axisSorters.add(layer.getSorter());
					if(layer.getSorter().isBreakingHierarchy())
						breaks_hierarchy = true;
				}
			}
			
			if(breaks_hierarchy){
				for(Iterator<Sorter> it = axisSorters.iterator(); it.hasNext();){
					Sorter sorter =  it.next();
					if(sorter.isBelongs_to_hierarchy())
						it.remove();
				}
			}
			
			for(Sorter sorter : axisSorters){
				if(sorter.getColumn()!=null){
					sql.addOrdering(sorter.getColumn(), sorter.getDirection());
				}else{
					sql.addCustomOrdering(sorter.getExpression(), sorter.getDirection());
				}
			}
			
		}
	}


	private void buildSubQueries() throws OlapException {
	
		
		for(ResultAxis axis : resultAxes){
			
			for(LevelMemberSet layer : axis.getLayers()){
				filterLayer(layer);					
			}
			
		}
		
		for(LevelMemberSet layer : filterAxis.getLayers()){
			filterLayer(layer);					
		}
		
		
	}


	protected void filterLayer(LevelMemberSet layer) throws OlapException {
		OlapOp func =layer.getFunction();
		if(func!=null){
			SetSubquery sub_query = func.query(mapping, layer);
			if(sub_query!=null){
				
				Condition condition = sub_query.condition();
				if(condition!=null)
					addCondition(condition);

				Condition having_condition = sub_query.havingCondition();
				if(having_condition!=null)
					addHavingCondition(having_condition);
				
			}
				

		}
	}



	protected void buildColumns() throws OlapException {
		DbTable fromTable = null;
		for(ResultAxis axis : resultAxes){
			
			for(LevelMemberSet layer : axis.getLayers()){
				
				if(layer.isMeasure()){
					
					for(Member m : layer.getMembers()){
						TableMapping.MeasureMapping mmap = mapping.getMapping((ServerMeasure) m);						