.
*/
/** ***********************************************************
*
*
* PURPOSE:
*
*
*
* COMMENTS:
*
*
*********************************************************** */
package rasj.odmg;
import org.odmg.*;
import rasj.*;
import rasj.clientcommhttp.*;
import rasj.global.*;
import java.util.*;
import java.io.*;
/**
* This class implements the ODMG OQLQuery interface.
*
* @version 1.0 (07-Apr-2000)
*
* @author Peter Zoller
*/
public class RasOQLQuery implements OQLQuery, RasCommDefs
{
/**
* This variable holds a reference to the RasImplementation object which created
* this RasOQLQuery object
*/
//private RasODMGImplementation rasImplementation=null;
private RasImplementationInterface rasImplementation=null;
/**
* Stores the query string.
*/
private String queryString = "";
/**
* Stores the MDD parameter list
*/
private LinkedList qParams = null;
/**
* Stores the number of MDD parameters
*/
private int numberOfParams = 0;
/**
* Constructor
*/
public RasOQLQuery(RasImplementationInterface imp)//RasODMGImplementation imp)
{
Debug.enterVerbose( "RasOQLQuery.constructor start." );
rasImplementation=imp;
Debug.leaveVerbose( "RasOQLQuery.constructor done." );
}
/**
* Defines the query to be executed.
*
* @param query The OQL query string.
*/
public void create(String query) throws QueryInvalidException
{
Debug.talkVerbose( "RasOQLQuery.create query=" + query );
queryString = query;
}
/**
* Binds a parameter to the query.
*/
public void bind(Object parameter)
throws QueryParameterCountInvalidException, QueryParameterTypeInvalidException
{
Debug.enterVerbose( "RasOQLQuery.bind start." );
// add the parameter to the set
if(qParams == null) qParams = new LinkedList();
qParams.add(parameter);
numberOfParams++;
Debug.enterVerbose( "RasOQLQuery.bind done." );
}
/**
* Execute the OQL query.
*/
public Object execute() throws QueryException
{
Debug.enterVerbose( "RasOQLQuery.execute start." );
BenchmarkTimer rasjQueryTimer = new BenchmarkTimer("rasjQuery");
rasjQueryTimer.startTimer();
String mddData = null;
String params = null;
String dummy = null;
//RasHttpRequest request;
Object item;
StringBuffer buff;
int offset;
int buffIndex;
Object result = null;
try
{
String errorMsg = "Could not execute OQL-Query: ";
// test if database is open
if(rasImplementation.dbIsOpen() == 0)
{
Debug.leaveVerbose( "RasQOLQuery.execute done. database not open." );
throw new DatabaseClosedException(errorMsg + "database not open");
}
// test if we have an open transaction
params = "ClientID=" + rasImplementation.getClientID() + "&Command=" + RasODMGGlobal.commIsOpenTA;
/*
request = new RasHttpRequest();
request.execute(rasImplementation.getRasServer(),params);//RasODMGGlobal.getRasServer(),params);
if(request.getResultType() == 98)
throw new TransactionNotInProgressException(errorMsg + "no open transaction");
*/
if(rasImplementation.isOpenTA()==false)
{
Debug.leaveVerbose( "RasQOLQuery.execute done. Error: no open transaction." );
throw new TransactionNotInProgressException(errorMsg + "no open transaction");
}
// test for correct number of query parameters
StringTokenizer strTok = new StringTokenizer(queryString);
String token = "";
int counter = 0;
while(strTok.hasMoreTokens())
{
token = strTok.nextToken();
if(token.charAt(0) == '$')
{
try
{
if(Integer.parseInt(token.substring(1, 2)) > counter)
counter++;
}
catch(NumberFormatException e)
{
// should not happen!
Debug.leaveVerbose( "RasOQLQuery.execute done. number format exception in query parsing." );
throw new QueryParameterCountInvalidException("There are was a NumberFormatException while parsing the query.");
}
}
}
if(counter != numberOfParams)
{
Debug.leaveVerbose( "RasOQLQuery.execute done. number of parameters does not match query." );
throw new QueryParameterCountInvalidException( counter + " variable(s) in the query string vs. " + numberOfParams + " parameter(s) bound to the query.");
}
// process the parameters
dummy = queryString.trim();
queryString = dummy;
if(numberOfParams > 0)
{
counter = 0;
ListIterator iter = qParams.listIterator(0);
while (iter.hasNext())
{
counter++;
item = iter.next();
if(item instanceof RasGMArray)
{
// we have a MDD parameter => substitute the $x occurance in
// the query string with #MDDx# and get the transfer encoding of
// the MDDs. The format is specified in the file
// clientcommhttp/RasHttprequest.java.
RasGMArray mdd = (RasGMArray)item;
if(mddData == null)
mddData = utils.getTransferEncoding(mdd);
else
mddData = mddData + utils.getTransferEncoding(mdd);
queryString = utils.substitute(queryString,"$"+counter,"#MDD"+counter+"#");
}
else
{
// no MDD parameter => substitute each occurence of the
// corresponding $ parameter in the query string with the
// value of this parameter
queryString = utils.substitute(queryString,"$"+counter,item.toString());
iter.remove();
numberOfParams--;
}
}
}
// what kind of query do we have?
// FIXME: this way you don't see it keyword is in comment, and you miss mixed case!! -- PB 2003-jun-15
if((queryString.indexOf("select") != -1) || (queryString.indexOf("SELECT") != -1))
{
//select query
params = "Command=" + RasODMGGlobal.commQueryExec + "&ClientID=" +
rasImplementation.getClientID() + "&QueryString=" + queryString;
}
else
{
// update query
params = "Command=" + RasODMGGlobal.commUpdateQueryExec + "&ClientID=" +
rasImplementation.getClientID() + "&QueryString=" + queryString +
"&Endianess=" + BIG_ENDIAN + "&NumberOfQueryParameters=" +
numberOfParams;
if(numberOfParams > 0)
params = params + "&BinDataSize=" + mddData.length() + "&BinData=" + mddData;
}
//request.execute(rasImplementation.getRasServer(),params);//RasODMGGlobal.getRasServer(),params);
//return request.getResult();
result = rasImplementation.queryRequest(params);
}
catch(RasQueryExecutionFailedException e)
{
Debug.leaveVerbose( "RasOQLQuery.execute done. query execution failed: " + e.getMessage() );
throw new QueryException(e.getMessage());
}
catch(IOException e2)
{
Debug.leaveVerbose( "RasOQLQuery.execute done. error while generating transfer encoding: " + e2.getMessage() );
throw new QueryException("Error while generating transfer encoding:\n" + e2.getMessage());
}
rasjQueryTimer.stopTimer();
rasjQueryTimer.print();
Debug.leaveVerbose( "RasOQLQuery.execute done. result=" + result );
return result;
} // execute()
} // RasOQLQuery
/*
* Utilities
*/
abstract class utils
{
static String substitute(final String sourceString, final String oldString, final String newString)
{
Debug.enterVerbose( "utils.substitute start." );
StringBuffer buff = new StringBuffer(sourceString);
int offset = 0;
int buffIndex = sourceString.indexOf(oldString,offset);
while(buffIndex != -1)
{
buff.replace(buffIndex,buffIndex+oldString.length(),newString);
offset = buffIndex+1;
buffIndex = buff.toString().indexOf(oldString,offset);
}
String result = buff.toString();
Debug.leaveVerbose( "utils.substitute done. result=" + result );
return result;
}
/** returns a byte array representing the GMArray. This byte array is used for uploading query
* parameters to the server.
* The exact format of the byte array is described in the documentation of class
* @see rasj.clientcommhttp.RasHttpRequest.
*/
static String getTransferEncoding(RasGMArray mdd) throws IOException
{
Debug.enterVerbose( "utils.getTransferEncoding start." );
String tileDomain = null;
RasMInterval domain = mdd.spatialDomain();
long typeLength = mdd.getTypeLength();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
DataOutputStream dStream = new DataOutputStream(outStream);
// get tilingDomain from the storageLayout object
if(mdd.getStorageLayout().getSpatialDomain() == null)
{
tileDomain = getTilingDomain(domain,typeLength,mdd.getStorageLayout());
}
else
tileDomain = mdd.getStorageLayout().getSpatialDomain().toString();
// write object type
//dStream.writeInt((int)getObjectType());
dStream.writeInt(1);
dStream.writeBytes(mdd.getObjectTypeName()+String.valueOf('\0'));
dStream.writeBytes(mdd.getTypeStructure()+String.valueOf('\0'));
dStream.writeInt((int)typeLength);
dStream.writeBytes(domain+String.valueOf('\0'));
dStream.writeBytes(tileDomain+String.valueOf('\0'));
dStream.writeBytes(mdd.getOID().toString()+String.valueOf('\0'));
// if we have an MArray of type ulong: test that each cell value does not
// exceed 2^32, because the server does only store 4 byte ushorts, and
// convert the java-8-byte-long-array to a java-byte-array containing
// only the 4 least bytes of each long value.
if(mdd instanceof RasMArrayLong)
{
int arraySize = (int)mdd.getArraySize();
byte[] longArray = mdd.getArray();
// we skip the first 4 bytes of each long => arraySize / 2
dStream.writeInt(arraySize / 2);
for(int i=0; i throw exception
if(longArray[i+j] != 0)
{
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(longArray));
dis.skipBytes(i);
long illegalValue = dis.readLong();
Debug.leaveVerbose( "utils.getTransferEncoding done. illegal long value." );
throw new RasIllegalULongValueException(illegalValue);
}
}
for(int j=4; j arraySize / 2
dStream.writeInt(arraySize / 2);
for(int i=0; i throw exception
if(intArray[i+j] != 0)
{
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(intArray));
dis.skipBytes(i);
int illegalValue = dis.readInt();
Debug.leaveVerbose( "utils.getTransferEncoding done. illegal short value." );
throw new RasIllegalUShortValueException(illegalValue);
}
}
for(int j=2; j