/*
* (C) Copyright IBM Corp. 2011
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.gaiandb.lite;
import java.sql.SQLException;
import java.util.Arrays;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.types.DataValueDescriptor;
import org.apache.derby.vti.IFastPath;
import com.ibm.db2j.GaianQuery;
import com.ibm.db2j.GaianTable;
import com.ibm.gaiandb.GaianResultSetMetaData;
import com.ibm.gaiandb.Logger;
/**
* A statement used to map a "table" into a "result".
* GaianTable, GaianQuery and indeed other VTI implementations have an ordered list of columns they expose just like
* any physical database table would. However, this LiteGaianStatement is instantiated as a JDBC statement which is executed
* then used to expose a "result" whose columns need to represent the result columns specified in the SQL query.
* Therefore, we have to map the column results from the tableMetaData structure into the resultMetaData structure at extraction time.
*
* Furthermore, there may also be result columns that are expressed in the SQl as compound expressions which may or not include
* any number of columns from the logical table, as well as functions and arithmetic.
*
* @author DavidVyvyan
*
*/
public class LiteGaianStatement extends GaianTable implements TableResultExtractor {
// Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2011";
private static final Logger logger = new Logger( "LiteGaianStatement", 30 );
private DataValueDescriptor[] rowTemplateForExposedColumns = null; // table row sent down to the GaianVTI at fetch time before being reduced to a result row
private GaianResultSetMetaData tableMetaData = null; // meta data for all columns in the table
private GaianResultSetMetaData resultMetaData = null; // meta data for all cols of the query result
private int[] resultColumns = null; // subset of table columns - expected as result of query by the calling code
@Override
public GaianResultSetMetaData getTableMetaData() throws SQLException { return tableMetaData; }
public void setResultColumns(int[] resultColumns) { this.resultColumns = resultColumns; }
public LiteGaianStatement() throws Exception {}
public LiteGaianStatement(String logicalTable, String tableArguments) throws Exception {
this(logicalTable, tableArguments, null, null);
}
public LiteGaianStatement(String logicalTable, String tableArguments, String tableDefinition, String forwardingNode) throws Exception {
super(logicalTable, tableArguments, tableDefinition, forwardingNode);
initialise( super.getMetaData() );
}
private void initialise( GaianResultSetMetaData tableMetaData ) throws SQLException {
this.tableMetaData = tableMetaData;
DataValueDescriptor[] temp = tableMetaData.getRowTemplate();
rowTemplateForExposedColumns = new DataValueDescriptor[temp.length];
for ( int i=0; i<rowTemplateForExposedColumns.length; i++ )
rowTemplateForExposedColumns[i] = temp[i].getNewNull();
logger.logThreadInfo("Resolved vtiRow from tableMetaData: " + tableMetaData + ", template: " + Arrays.asList(temp));
}
@Override
public GaianResultSetMetaData getMetaData() throws SQLException {
if ( null == resultMetaData ) {
if ( null == resultColumns )
resultMetaData = tableMetaData; // all cols selected in query
else {
StringBuffer sb = new StringBuffer();
if ( 0 < resultColumns.length )
sb.append( tableMetaData.getColumnDescription(resultColumns[0]) );
for ( int i=1; i<resultColumns.length; i++ )
sb.append( ", " + tableMetaData.getColumnDescription(resultColumns[i]) );
try {
resultMetaData = new GaianResultSetMetaData(sb.toString());
} catch (Exception e) { throw new SQLException(e); }
logger.logThreadInfo("Resolved resultMetaData: " + resultMetaData);
}
}
return resultMetaData;
}
@Override
public int nextRow( DataValueDescriptor[] resultRow ) throws StandardException, SQLException {
return null == resultColumns ? super.nextRow(resultRow) : getResultRow( super.nextRow(rowTemplateForExposedColumns), resultRow );
}
private int getResultRow( int rc, DataValueDescriptor[] resultRow ) throws StandardException {
if ( IFastPath.SCAN_COMPLETED != rc )
for ( int i=0; i<resultColumns.length; i++ )
resultRow[i].setValue( rowTemplateForExposedColumns[ resultColumns[i]-1 ] );
return rc;
}
public class LiteGaianQueryStatement extends GaianQuery implements TableResultExtractor {
public LiteGaianQueryStatement(String sqlQuery, String tableArguments, String queryArguments, String tableDef, String forwardingNode)
throws Exception {
super(sqlQuery, tableArguments, queryArguments, tableDef, forwardingNode);
initialise( super.getMetaData() );
}
@Override
public GaianResultSetMetaData getMetaData() throws SQLException {
return LiteGaianStatement.this.getMetaData();
}
@Override
public int nextRow( DataValueDescriptor[] resultRow ) throws StandardException, SQLException {
return null == resultColumns ? super.nextRow(resultRow) : getResultRow( super.nextRow(rowTemplateForExposedColumns), resultRow );
}
@Override
public GaianResultSetMetaData getTableMetaData() throws SQLException {
return LiteGaianStatement.this.getTableMetaData();
}
public void setResultColumns(int[] resultColumns) {
LiteGaianStatement.this.resultColumns = resultColumns;
}
}
}