/*
* (C) Copyright IBM Corp. 2008
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.db2j;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Map;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.store.access.Qualifier;
import org.apache.derby.iapi.types.DataValueDescriptor;
import org.apache.derby.vti.IFastPath;
import org.apache.derby.vti.VTICosting;
import org.apache.derby.vti.VTIEnvironment;
import com.ibm.gaiandb.CachedHashMap;
import com.ibm.gaiandb.GaianChildVTI;
import com.ibm.gaiandb.GaianDBConfigProcedures;
import com.ibm.gaiandb.Logger;
import com.ibm.gaiandb.Util;
import com.ibm.gaiandb.diags.GDBMessages;
public class GaianConfig extends VTI60 implements VTICosting, IFastPath, GaianChildVTI {
// Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2008";
private static final Logger logger = new Logger( "GaianConfig", 20 );
private final String configRequest;
private String additionalParams = null;
private DataValueDescriptor[][] resultRows = null;
private int index = 0;
// search sring -> latest row count
private static Map<String, Long> estimatedRowCounts =
Collections.synchronizedMap( new CachedHashMap<String, Long>( GaianTable.QRY_METADATA_CACHE_SIZE ) );
private ResultSetMetaData rsmd;
/**
* @param configRequest
* @throws Exception
*/
public GaianConfig(String configRequest) throws Exception {
super();
logger.logDetail("Entered GaianConfig(configRequest) constructor");
this.configRequest = configRequest;
}
/**
* @param configRequest
* @param additionalParams - String - CSV list of additional parameters for the request. Null if none.
* @throws Exception
*/
public GaianConfig(String configRequest, String additionalParams) throws Exception {
super();
logger.logDetail("Entered GaianConfig(configRequest, additionalParams) constructor");
this.configRequest = configRequest;
this.additionalParams = additionalParams;
}
/* (non-Javadoc)
* @see com.ibm.gaiandb.GaianChildVTI#setArgs(java.lang.String[])
*/
public void setArgs(String[] args) {
// if ( null != args && 0 < args.length ) this.configRequest = args[0];
}
/* (non-Javadoc)
* @see com.ibm.gaiandb.GaianChildVTI#setExtractConditions(org.apache.derby.iapi.store.access.Qualifier[][], int[])
*/
public void setExtractConditions(Qualifier[][] qualifiers, int[] logicalProjection, int[] columnsMapping) throws SQLException {
// Qualifiers and column mappings are not supported for this VTI - as it is mostly used by the API list commands...
// No need to set qualifiers - the search string acts as a filter instead.
// Also ignore mappedColumns as column names are expected to be the same in the logical table.
executeAsFastPath();
}
/* (non-Javadoc)
* @see org.apache.derby.vti.IFastPath#executeAsFastPath()
*/
public boolean executeAsFastPath() throws SQLException {
logger.logDetail("Entered GaianConfig.executeAsFastPath()");
if ( null != resultRows ) {
logger.logDetail("Old results still in memory - closing..");
close();
// return true;
}
index = 0;
try {
resultRows = GaianDBConfigProcedures.getResultSetForUtilityRequest( configRequest, additionalParams );
} catch (Exception e) {
logger.logException(GDBMessages.ENGINE_GET_ROWS_FOR_CONFIG_ERROR, "Unable to get rows for config request: " + configRequest + ", cause: ", e);
throw new SQLException( e.getMessage() );
}
logger.logDetail("Exiting GaianConfig.executeAsFastPath(), resultRows.length: " + resultRows.length);
return true;
}
/* (non-Javadoc)
* @see org.apache.derby.vti.IFastPath#nextRow(org.apache.derby.iapi.types.DataValueDescriptor[])
*/
public int nextRow(DataValueDescriptor[] dvdr) throws StandardException, SQLException {
if ( 0 == index )
logger.logDetail("Fetching rows for GaianConfig('" + configRequest + "')");
if ( index >= resultRows.length ) {
// logger.logDetail("Fetch complete for GaianConfig('" + configRequest + "')");
// Keep track of row count for this search string
Long previousCount = estimatedRowCounts.get( configRequest );
if ( null == previousCount || index > previousCount.longValue() )
estimatedRowCounts.put( configRequest, new Long( index ) );
index = 0;
return IFastPath.SCAN_COMPLETED;
}
System.arraycopy(resultRows[index++], 0, dvdr, 0, resultRows[0].length);
// for ( int i=0; i<numCols; i++ ) dvdr[i].setValue( row[i] );
return IFastPath.GOT_ROW;
}
/* (non-Javadoc)
* @see org.apache.derby.vti.IFastPath#currentRow(java.sql.ResultSet, org.apache.derby.iapi.types.DataValueDescriptor[])
*/
public void currentRow(ResultSet arg0, DataValueDescriptor[] arg1) throws StandardException, SQLException {
}
/* (non-Javadoc)
* @see org.apache.derby.vti.IFastPath#rowsDone()
*/
public void rowsDone() throws StandardException, SQLException {
close();
}
/**
* Provide the metadata for the query against the given table. Cloudscape
* calls this method when it compiles the SQL-J statement that uses this
* VTI class.
*
* @return the result set metadata for the query
*
* @exception SQLException thrown by JDBC calls
*/
public ResultSetMetaData getMetaData() throws SQLException {
if ( null == rsmd ) {
try {
rsmd = (ResultSetMetaData) GaianDBConfigProcedures.configRequestResultDefs.get(
Util.splitByCommas(configRequest)[0]);
} catch (Exception e) {
throw new SQLException(e+"");
}
}
logger.logDetail("getMetaData(): " + rsmd + " - " + configRequest);
return rsmd;
}
public void close() {
logger.logDetail("GaianConfig.close()");
reinitialise();
}
/**
* Re-initialises and tells us whether the VTI can be re-executed
*/
@Override public boolean reinitialise() {
logger.logDetail("GaianConfig.reinitialise()");
if ( null != resultRows ) {
for (int i=0; i<resultRows.length; i++) {
for (int j=0; j<resultRows[i].length; j++)
resultRows[i][j] = null;
resultRows[i] = null;
}
resultRows = null;
}
index = 0;
return true;
}
public boolean isBeforeFirst() {
return 0 == index;
}
/* (non-Javadoc)
* @see org.apache.derby.vti.VTICosting#getEstimatedRowCount(org.apache.derby.vti.VTIEnvironment)
*/
public double getEstimatedRowCount(VTIEnvironment arg0) throws SQLException {
Long l = estimatedRowCounts.get( configRequest );
double val = null == l ? 1000 : l.doubleValue() * 10; // multiply by 10 as this is XML!
logger.logDetail("getEstimatedRowCount() returning: " + val);
return val;
}
/* (non-Javadoc)
* @see org.apache.derby.vti.VTICosting#getEstimatedCostPerInstantiation(org.apache.derby.vti.VTIEnvironment)
*/
public double getEstimatedCostPerInstantiation(VTIEnvironment arg0) throws SQLException {
int rc = 0;
logger.logDetail("getEstimatedCostPerInstantiation() returning: " + rc);
return rc;
}
/* (non-Javadoc)
* @see org.apache.derby.vti.VTICosting#supportsMultipleInstantiations(org.apache.derby.vti.VTIEnvironment)
*/
public boolean supportsMultipleInstantiations(VTIEnvironment arg0) throws SQLException {
// For us to return true, we must ensure that results can be fetched repeatedly.
// i.e. that the cursor is set back to the first row every time we reach the end of it.
boolean rc = true;
logger.logDetail("supportsMultipleInstantiations() returning: " + rc);
return rc;
}
public boolean fetchNextRow(DataValueDescriptor[] row) throws Exception {
return IFastPath.GOT_ROW == nextRow(row);
}
public int getRowCount() throws Exception {
return null == resultRows ? 0 : resultRows.length;
}
public boolean isScrollable() {
return true;
}
@Override
public int getResultSetType() throws SQLException {
return ResultSet.TYPE_FORWARD_ONLY;
}
@Override
public int getResultSetConcurrency() throws SQLException {
return ResultSet.CONCUR_UPDATABLE;
}
}