/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright 2005 - 2009 Pentaho Corporation. All rights reserved.
*
*
* Created Sep 12, 2005
* @author wseyler
*/
package org.pentaho.platform.plugin.services.connections.mondrian;
import mondrian.olap.Connection;
import mondrian.olap.Result;
import org.pentaho.commons.connection.IMultiDimensionalResultSet;
import org.pentaho.commons.connection.IPeekable;
import org.pentaho.commons.connection.IPentahoMetaData;
import org.pentaho.commons.connection.IPentahoResultSet;
import org.pentaho.commons.connection.memory.MemoryMetaData;
import org.pentaho.commons.connection.memory.MemoryResultSet;
/**
* @author wseyler
*
* TODO To change the template for this generated type comment go to Window -
* Preferences - Java - Code Style - Code Templates
*/
public class MDXResultSet implements IPentahoResultSet, IPeekable, IMultiDimensionalResultSet {
private Result nativeResultSet;
private Connection nativeConnection;
private int rowIndex = 0;
private MDXMetaData mdxMetaData = null;
private Object peekRow[];
private boolean formattedCellValues = false; // should we return formatted or plain cell values
public MDXResultSet() {
}
/**
* @param useExtendedColumnNames if true, columnNames will follow the format:
* "[dimension_name].[hierarchy_name].[level_name]"
* otherwise the format for column names will be:
* "hierarchy_name{column_number}"
*
* Implemented as a flag to allow reports prior to platform version 2.1
* (Liberty) to continue to execute as expected with the short column names,
* but if the developer sets the extendedColumnNames flag to true, can overcome the
* bug in BISERVER-1266.
*
* @param returnNullCells if true, returns null instead of 0.000000012345. This is
* configurable for backwards compatibility
*
*/
public MDXResultSet(final Result nativeResultSet, final Connection nativeConnection, boolean useExtendedColumnNames) {
super();
this.nativeResultSet = nativeResultSet;
this.nativeConnection = nativeConnection;
mdxMetaData = new MDXMetaData(this.nativeResultSet, useExtendedColumnNames);
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#getMetaData()
*/
public IPentahoMetaData getMetaData() {
return mdxMetaData;
}
public Object[] peekRowHeaders() {
int peekRowNo = rowIndex;
if (peekRowNo < getRowCount()) {
return mdxMetaData.getRowHeaders()[peekRowNo];
}
return null;
}
public Object[] peek() {
if( peekRow == null ) {
peekRow = next();
}
return peekRow;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#next()
*/
public Object[] next() {
if (peekRow != null) {
Object row[] = peekRow;
peekRow = null;
return row;
}
Object currentRow[] = null;
int columnCount = getColumnCount();
if (rowIndex < getRowCount()) {
currentRow = new Object[columnCount];
for (int i = 0; i < columnCount; i++) {
currentRow[i] = getValueAt(rowIndex, i);
}
rowIndex++;
}
return currentRow;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#close()
*/
public void close() {
nativeResultSet.close();
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#closeConnection()
*/
public void closeConnection() {
nativeResultSet.close();
nativeConnection.close();
}
/*
* (non-Javadoc)
*
* @see org.pentaho.core.runtime.IDisposable#dispose()
*/
public void dispose() {
closeConnection();
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#isScrollable()
*/
public boolean isScrollable() {
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#getValueAt(int, int)
*/
public Object getValueAt(final int row, final int column) {
int[] key = new int[2];
key[0] = column;
key[1] = row;
if( formattedCellValues ) {
return nativeResultSet.getCell(key).getFormattedValue();
} else {
return nativeResultSet.getCell(key).getValue();
}
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#getRowCount()
*/
public int getRowCount() {
return mdxMetaData.getRowHeaders().length;
}
/*
* (non-Javadoc)
*
* @see org.pentaho.connection.IPentahoResultSet#getColumnCount()
*/
public int getColumnCount() {
return mdxMetaData.getColumnCount();
}
public IPentahoResultSet memoryCopy() {
try {
IPentahoMetaData metadata = getMetaData();
Object columnHeaders[][] = metadata.getColumnHeaders();
Object rowHeaders[][] = metadata.getRowHeaders();
MemoryMetaData cachedMetaData = new MemoryMetaData(columnHeaders, rowHeaders);
MemoryResultSet cachedResultSet = new MemoryResultSet(cachedMetaData);
Object[] rowObjects = next();
while (rowObjects != null) {
cachedResultSet.addRow(rowObjects);
rowObjects = next();
}
return cachedResultSet;
} finally {
close();
}
}
public void beforeFirst() {
rowIndex = 0;
}
public Object[] getDataColumn(final int column) {
int oldIndex = rowIndex; // save our current iteration location
beforeFirst();
Object[] result = new Object[getRowCount()];
int index = 0;
Object[] rowData = next();
while (rowData != null) {
result[index] = rowData[column];
index++;
rowData = next();
}
rowIndex = oldIndex; // restore the old iteration location
return result;
}
public Object[] getDataRow(final int row) {
int oldIndex = rowIndex; // save our current iteration location
rowIndex = row;
Object[] rowData = next();
rowIndex = oldIndex;
return rowData;
}
protected Result getNativeResultSet() {
return nativeResultSet;
}
protected void setNativeResultSet(Result nativeResultSet) {
this.nativeResultSet = nativeResultSet;
}
protected Connection getNativeConnection() {
return nativeConnection;
}
protected void setNativeConnection(Connection nativeConnection) {
this.nativeConnection = nativeConnection;
}
protected MDXMetaData getMdxMetaData() {
return mdxMetaData;
}
protected void setMdxMetaData(MDXMetaData mdxMetaData) {
this.mdxMetaData = mdxMetaData;
}
protected Object[] getPeekRow() {
return peekRow;
}
protected void setPeekRow(Object[] peekRow) {
this.peekRow = peekRow;
}
public int getRowIndex() {
return rowIndex;
}
public Object[] nextFlattened() {
Object rowHeaders[][] = mdxMetaData.getRowHeaders();
if( rowHeaders == null ) {
// we have no row headers so we can call the regular next()
return next();
}
// get the row
Object row[] = next();
if( row == null ) {
// we have got to the end
return null;
}
// do we have row headers to return also?
if( rowIndex <= rowHeaders.length ) {
// pull out the right row headers
Object rowHeads[] = rowHeaders[rowIndex-1];
// create the flattened row
Object flatRow[] = new Object[rowHeads.length+row.length];
// copy in the row headers and row objects
System.arraycopy(rowHeads, 0, flatRow, 0, rowHeads.length);
System.arraycopy(row, 0, flatRow, rowHeads.length, row.length);
return flatRow;
}
return row;
}
public Object[] peekFlattened() {
Object rowHeaders[][] = mdxMetaData.getRowHeaders();
if( rowHeaders == null ) {
// we have no row headers so we can call the regular peek()
return peek();
}
// get the row
Object row[] = peek();
if( row == null ) {
// we have got to the end
return null;
}
// do we have row headers to return also?
if( rowIndex <= rowHeaders.length ) {
// pull out the right row headers
Object rowHeads[] = rowHeaders[rowIndex-1];
// create the flattened row
Object flatRow[] = new Object[rowHeads.length+row.length];
// copy in the row headers and row objects
System.arraycopy(rowHeads, 0, flatRow, 0, rowHeads.length);
System.arraycopy(row, 0, flatRow, rowHeads.length, row.length);
return flatRow;
}
return row;
}
/**
* Sets the 'formatted cell values' flag. If this flag is set calls to
* getValueAt (and methods like next() and peek() that use getValueAt)
* returns the formatted value of the cell instead of the plain number.
* BISERVER-3543
* @param formattedCellValues
*/
public void setFormattedCellValues( boolean formattedCellValues ) {
this.formattedCellValues = formattedCellValues;
}
}